[2/2] libx264: Pass the reordered_opaque field through the encoder

Message ID 20181025124521.30217-2-martin@martin.st
State New
Headers show
Series
  • [1/2] libavutil: Undeprecate the AVFrame reordered_opaque field
Related show

Commit Message

Martin Storsjö Oct. 25, 2018, 12:45 p.m.
libx264 does have a field for opaque data to pass along with frames
through the encoder, but it is a pointer, while the libavcodec
reordered_opaque field is an int64_t. Therefore, allocate an array
within the libx264 wrapper, where reordered_opaque values in flight
are stored, and pass a pointer to this array to libx264.

Update the public libavcodec documentation for the AVCodecContext
field to explain this usage, and add a codec capability that allows
detecting whether an encoder handles this field.
---
 libavcodec/avcodec.h | 12 +++++++++++-
 libavcodec/libx264.c | 31 +++++++++++++++++++++++++++++--
 2 files changed, 40 insertions(+), 3 deletions(-)

Comments

Martin Storsjö Oct. 25, 2018, 12:52 p.m. | #1
On Thu, 25 Oct 2018, Martin Storsjö wrote:

> libx264 does have a field for opaque data to pass along with frames
> through the encoder, but it is a pointer, while the libavcodec
> reordered_opaque field is an int64_t. Therefore, allocate an array
> within the libx264 wrapper, where reordered_opaque values in flight
> are stored, and pass a pointer to this array to libx264.
>
> Update the public libavcodec documentation for the AVCodecContext
> field to explain this usage, and add a codec capability that allows
> detecting whether an encoder handles this field.
> ---
> libavcodec/avcodec.h | 12 +++++++++++-
> libavcodec/libx264.c | 31 +++++++++++++++++++++++++++++--
> 2 files changed, 40 insertions(+), 3 deletions(-)
>
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index fb8e34e7d5..727e1c411d 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -899,6 +899,13 @@ typedef struct RcOverride{
>  */
> #define AV_CODEC_CAP_HYBRID              (1 << 18)
> 
> +/**
> + * This codec takes the reordered_opaque field from input AVFrames
> + * and returns it in the corresponding field in AVCodecContext after
> + * encoding.
> + */
> +#define AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE (1 << 19)

This obviously needs a minor bump, I'll add one locally.

// Martin

Patch

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index fb8e34e7d5..727e1c411d 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -899,6 +899,13 @@  typedef struct RcOverride{
  */
 #define AV_CODEC_CAP_HYBRID              (1 << 18)
 
+/**
+ * This codec takes the reordered_opaque field from input AVFrames
+ * and returns it in the corresponding field in AVCodecContext after
+ * encoding.
+ */
+#define AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE (1 << 19)
+
 /**
  * Pan Scan area.
  * This specifies the area which should be displayed.
@@ -2297,7 +2304,10 @@  typedef struct AVCodecContext {
     /**
      * opaque 64-bit number (generally a PTS) that will be reordered and
      * output in AVFrame.reordered_opaque
-     * - encoding: unused
+     * - encoding: Set by libavcodec to the reordered_opaque of the input
+     *             frame corresponding to the last returned packet. Only
+     *             supported by encoders with the
+     *             AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE capability.
      * - decoding: Set by user.
      */
     int64_t reordered_opaque;
diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c
index 3dc53aaf38..c852858db8 100644
--- a/libavcodec/libx264.c
+++ b/libavcodec/libx264.c
@@ -85,6 +85,9 @@  typedef struct X264Context {
     int noise_reduction;
 
     char *x264_params;
+
+    int nb_reordered_opaque, next_reordered_opaque;
+    int64_t *reordered_opaque;
 } X264Context;
 
 static void X264_log(void *p, int level, const char *fmt, va_list args)
@@ -240,6 +243,7 @@  static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame,
     x264_nal_t *nal;
     int nnal, i, ret;
     x264_picture_t pic_out;
+    int64_t *out_opaque;
 
     x264_picture_init( &x4->pic );
     x4->pic.img.i_csp   = x4->params.i_csp;
@@ -259,6 +263,11 @@  static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame,
 
         x4->pic.i_pts  = frame->pts;
 
+        x4->reordered_opaque[x4->next_reordered_opaque] = frame->reordered_opaque;
+        x4->pic.opaque = &x4->reordered_opaque[x4->next_reordered_opaque];
+        x4->next_reordered_opaque++;
+        x4->next_reordered_opaque %= x4->nb_reordered_opaque;
+
         switch (frame->pict_type) {
         case AV_PICTURE_TYPE_I:
             x4->pic.i_type = x4->forced_idr ? X264_TYPE_IDR
@@ -288,6 +297,15 @@  static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame,
     pkt->pts = pic_out.i_pts;
     pkt->dts = pic_out.i_dts;
 
+    out_opaque = pic_out.opaque;
+    if (out_opaque >= x4->reordered_opaque &&
+        out_opaque < &x4->reordered_opaque[x4->nb_reordered_opaque]) {
+        ctx->reordered_opaque = *out_opaque;
+    } else {
+        // Unexpected opaque pointer on picture output
+        ctx->reordered_opaque = 0;
+    }
+
 #if FF_API_CODED_FRAME
 FF_DISABLE_DEPRECATION_WARNINGS
     switch (pic_out.i_type) {
@@ -331,6 +349,7 @@  static av_cold int X264_close(AVCodecContext *avctx)
 
     av_freep(&avctx->extradata);
     av_freep(&x4->sei);
+    av_freep(&x4->reordered_opaque);
 
     if (x4->enc) {
         x264_encoder_close(x4->enc);
@@ -663,6 +682,12 @@  FF_ENABLE_DEPRECATION_WARNINGS
     cpb_props->max_bitrate = x4->params.rc.i_vbv_max_bitrate * 1000;
     cpb_props->avg_bitrate = x4->params.rc.i_bitrate         * 1000;
 
+    x4->nb_reordered_opaque = x264_encoder_maximum_delayed_frames(x4->enc) + 1;
+    x4->reordered_opaque    = av_malloc_array(x4->nb_reordered_opaque,
+                                              sizeof(*x4->reordered_opaque));
+    if (!x4->reordered_opaque)
+        return AVERROR(ENOMEM);
+
     return 0;
 }
 
@@ -850,7 +875,8 @@  AVCodec ff_libx264_encoder = {
     .init             = X264_init,
     .encode2          = X264_frame,
     .close            = X264_close,
-    .capabilities     = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS,
+    .capabilities     = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS |
+                        AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
     .priv_class       = &class,
     .defaults         = x264_defaults,
     .init_static_data = X264_init_static,
@@ -877,7 +903,8 @@  AVCodec ff_libx262_encoder = {
     .init             = X264_init,
     .encode2          = X264_frame,
     .close            = X264_close,
-    .capabilities     = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS,
+    .capabilities     = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS |
+                        AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
     .priv_class       = &X262_class,
     .defaults         = x264_defaults,
     .pix_fmts         = pix_fmts_8bit,