This is intended to be a more convenient replacement for reordered_opaque. Add support for it in the two encoders that offer AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE: libx264 and libx265. Other encoders will be supported in future commits.
Unified · Split
| @@ -14,6 +14,9 @@ libavutil: 2021-04-27 · 13 unmodified lines | ||
| 14 | 14 | |
| 15 | 15 | API changes, most recent first: |
| 16 | 16 | |
| 17 | +2023-01-xx - xxxxxxxxxx - lavc 59.59.100 - avcodec.h | |
| 18 | + Add AV_CODEC_FLAG_COPY_OPAQUE. | |
| 19 | + | |
| 17 | 20 | 2023-01-13 - xxxxxxxxxx - lavu 57.44.100 - ambient_viewing_environment.h frame.h |
| 18 | 21 | Adds a new structure for holding H.274 Ambient Viewing Environment metadata, |
| 19 | 22 | AVAmbientViewingEnvironment. |
| @@ -241,6 +241,32 @@ typedef struct RcOverride{ · 240 unmodified lines | ||
| 241 | 241 | * @ref AV_CODEC_CAP_ENCODER_RECON_FRAME capability. |
| 242 | 242 | */ |
| 243 | 243 | #define AV_CODEC_FLAG_RECON_FRAME (1 << 6) |
| 244 | +/** | |
| 245 | + * Request the encoder to propagate each frame's AVFrame.opaque and | |
| 246 | + * AVFrame.opaque_ref values to its corresponding output AVPacket. | |
| 247 | + * | |
| 248 | + * May only be set on encoders that have the | |
| 249 | + * @ref AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE capability flag. | |
| 250 | + * | |
| 251 | + * @note | |
| 252 | + * While in typical cases one input frame produces exactly one output packet | |
| 253 | + * (perhaps after a delay), in general the mapping of frames to packets is | |
| 254 | + * M-to-N, so | |
| 255 | + * - Any number of input frames may be associated with any given output packet. | |
| 256 | + * This includes zero - e.g. some encoders may output packets that carry only | |
| 257 | + * metadata about the whole stream. | |
| 258 | + * - A given input frame may be associated with any number of output packets. | |
| 259 | + * Again this includes zero - e.g. some encoders may drop frames under certain | |
| 260 | + * conditions. | |
| 261 | + * . | |
| 262 | + * This implies that when using this flag, the caller must NOT assume that | |
| 263 | + * - a given input frame's opaques will necessarily appear on some output packet; | |
| 264 | + * - every output packet will have some non-NULL opaque value. | |
| 265 | + * . | |
| 266 | + * When an output packet contains multiple frames, the opaque values will be | |
| 267 | + * taken from the first of those. | |
| 268 | + */ | |
| 269 | +#define AV_CODEC_FLAG_COPY_OPAQUE (1 << 7) | |
| 244 | 270 | /** |
| 245 | 271 | * Use internal 2pass ratecontrol in first pass mode. |
| 246 | 272 | */ |
| @@ -636,6 +636,13 @@ int ff_encode_preinit(AVCodecContext *avctx) · 635 unmodified lines | ||
| 636 | 636 | return AVERROR(EINVAL); |
| 637 | 637 | } |
| 638 | 638 | |
| 639 | + if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE && | |
| 640 | + !(avctx->codec->capabilities & AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE)) { | |
| 641 | + av_log(avctx, AV_LOG_ERROR, "The copy_opaque flag is set, but the " | |
| 642 | + "encoder does not support it.\n"); | |
| 643 | + return AVERROR(EINVAL); | |
| 644 | + } | |
| 645 | + | |
| 639 | 646 | switch (avctx->codec_type) { |
| 640 | 647 | case AVMEDIA_TYPE_VIDEO: ret = encode_preinit_video(avctx); break; |
| 641 | 648 | case AVMEDIA_TYPE_AUDIO: ret = encode_preinit_audio(avctx); break; |
| @@ -21,6 +21,7 @@ · 20 unmodified lines | ||
| 21 | 21 | |
| 22 | 22 | #include "config_components.h" |
| 23 | 23 | |
| 24 | +#include "libavutil/buffer.h" | |
| 24 | 25 | #include "libavutil/eval.h" |
| 25 | 26 | #include "libavutil/internal.h" |
| 26 | 27 | #include "libavutil/opt.h" |
| @@ -51,6 +52,9 @@ · 24 unmodified lines | ||
| 51 | 52 | typedef struct X264Opaque { |
| 52 | 53 | int64_t reordered_opaque; |
| 53 | 54 | int64_t wallclock; |
| 55 | + | |
| 56 | + void *frame_opaque; | |
| 57 | + AVBufferRef *frame_opaque_ref; | |
| 54 | 58 | } X264Opaque; |
| 55 | 59 | |
| 56 | 60 | typedef struct X264Context { |
| @@ -133,6 +137,11 @@ static void X264_log(void *p, int level, const char *fmt, va_list args) · 76 unmodified lines | ||
| 133 | 137 | av_vlog(p, level_map[level], fmt, args); |
| 134 | 138 | } |
| 135 | 139 | |
| 140 | +static void opaque_uninit(X264Opaque *o) | |
| 141 | +{ | |
| 142 | + av_buffer_unref(&o->frame_opaque_ref); | |
| 143 | + memset(o, 0, sizeof(*o)); | |
| 144 | +} | |
| 136 | 145 | |
| 137 | 146 | static int encode_nals(AVCodecContext *ctx, AVPacket *pkt, |
| 138 | 147 | const x264_nal_t *nals, int nnal) |
| @@ -440,6 +449,15 @@ static int setup_frame(AVCodecContext *ctx, const AVFrame *frame, · 301 unmodified lines | ||
| 440 | 449 | |
| 441 | 450 | pic->i_pts = frame->pts; |
| 442 | 451 | |
| 452 | + opaque_uninit(opaque); | |
| 453 | + | |
| 454 | + if (ctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) { | |
| 455 | + opaque->frame_opaque = frame->opaque; | |
| 456 | + ret = av_buffer_replace(&opaque->frame_opaque_ref, frame->opaque_ref); | |
| 457 | + if (ret < 0) | |
| 458 | + goto fail; | |
| 459 | + } | |
| 460 | + | |
| 443 | 461 | opaque->reordered_opaque = frame->reordered_opaque; |
| 444 | 462 | opaque->wallclock = wallclock; |
| 445 | 463 | if (ctx->export_side_data & AV_CODEC_EXPORT_DATA_PRFT) |
| @@ -594,6 +612,14 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame, · 148 unmodified lines | ||
| 594 | 612 | out_opaque < &x4->reordered_opaque[x4->nb_reordered_opaque]) { |
| 595 | 613 | ctx->reordered_opaque = out_opaque->reordered_opaque; |
| 596 | 614 | wallclock = out_opaque->wallclock; |
| 615 | + | |
| 616 | + if (ctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) { | |
| 617 | + pkt->opaque = out_opaque->frame_opaque; | |
| 618 | + pkt->opaque_ref = out_opaque->frame_opaque_ref; | |
| 619 | + out_opaque->frame_opaque_ref = NULL; | |
| 620 | + } | |
| 621 | + | |
| 622 | + opaque_uninit(out_opaque); | |
| 597 | 623 | } else { |
| 598 | 624 | // Unexpected opaque pointer on picture output |
| 599 | 625 | av_log(ctx, AV_LOG_ERROR, "Unexpected opaque pointer; " |
| @@ -634,6 +660,9 @@ static av_cold int X264_close(AVCodecContext *avctx) · 34 unmodified lines | ||
| 634 | 660 | X264Context *x4 = avctx->priv_data; |
| 635 | 661 | |
| 636 | 662 | av_freep(&x4->sei); |
| 663 | + | |
| 664 | + for (int i = 0; i < x4->nb_reordered_opaque; i++) | |
| 665 | + opaque_uninit(&x4->reordered_opaque[i]); | |
| 637 | 666 | av_freep(&x4->reordered_opaque); |
| 638 | 667 | |
| 639 | 668 | #if X264_BUILD >= 161 |
| @@ -28,6 +28,7 @@ · 27 unmodified lines | ||
| 28 | 28 | #include <float.h> |
| 29 | 29 | |
| 30 | 30 | #include "libavutil/avassert.h" |
| 31 | +#include "libavutil/buffer.h" | |
| 31 | 32 | #include "libavutil/internal.h" |
| 32 | 33 | #include "libavutil/common.h" |
| 33 | 34 | #include "libavutil/opt.h" |
| @@ -43,6 +44,9 @@ · 9 unmodified lines | ||
| 43 | 44 | typedef struct ReorderedData { |
| 44 | 45 | int64_t reordered_opaque; |
| 45 | 46 | |
| 47 | + void *frame_opaque; | |
| 48 | + AVBufferRef *frame_opaque_ref; | |
| 49 | + | |
| 46 | 50 | int in_use; |
| 47 | 51 | } ReorderedData; |
| 48 | 52 | |
| @@ -121,7 +125,7 @@ static int rd_get(libx265Context *ctx) · 72 unmodified lines | ||
| 121 | 125 | static void rd_release(libx265Context *ctx, int idx) |
| 122 | 126 | { |
| 123 | 127 | av_assert0(idx >= 0 && idx < ctx->nb_rd); |
| 124 | − | |
| 128 | + av_buffer_unref(&ctx->rd[idx].frame_opaque_ref); | |
| 125 | 129 | memset(&ctx->rd[idx], 0, sizeof(ctx->rd[idx])); |
| 126 | 130 | } |
| 127 | 131 | |
| @@ -132,6 +136,8 @@ static av_cold int libx265_encode_close(AVCodecContext *avctx) · 4 unmodified lines | ||
| 132 | 136 | ctx->api->param_free(ctx->params); |
| 133 | 137 | av_freep(&ctx->sei_data); |
| 134 | 138 | |
| 139 | + for (int i = 0; i < ctx->nb_rd; i++) | |
| 140 | + rd_release(ctx, i); | |
| 135 | 141 | av_freep(&ctx->rd); |
| 136 | 142 | |
| 137 | 143 | if (ctx->encoder) |
| @@ -582,6 +588,9 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, · 444 unmodified lines | ||
| 582 | 588 | sei->numPayloads = 0; |
| 583 | 589 | |
| 584 | 590 | if (pic) { |
| 591 | + ReorderedData *rd; | |
| 592 | + int rd_idx; | |
| 593 | + | |
| 585 | 594 | for (i = 0; i < 3; i++) { |
| 586 | 595 | x265pic.planes[i] = pic->data[i]; |
| 587 | 596 | x265pic.stride[i] = pic->linesize[i]; |
| @@ -600,21 +609,26 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, · 12 unmodified lines | ||
| 600 | 609 | if (ret < 0) |
| 601 | 610 | return ret; |
| 602 | 611 | |
| 603 | − if (pic->reordered_opaque) { | |
| 604 | − ReorderedData *rd; | |
| 605 | − int rd_idx = rd_get(ctx); | |
| 612 | + rd_idx = rd_get(ctx); | |
| 613 | + if (rd_idx < 0) { | |
| 614 | + free_picture(ctx, &x265pic); | |
| 615 | + return rd_idx; | |
| 616 | + } | |
| 617 | + rd = &ctx->rd[rd_idx]; | |
| 606 | 618 | |
| 607 | − if (rd_idx < 0) { | |
| 619 | + rd->reordered_opaque = pic->reordered_opaque; | |
| 620 | + if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) { | |
| 621 | + rd->frame_opaque = pic->opaque; | |
| 622 | + ret = av_buffer_replace(&rd->frame_opaque_ref, pic->opaque_ref); | |
| 623 | + if (ret < 0) { | |
| 624 | + rd_release(ctx, rd_idx); | |
| 608 | 625 | free_picture(ctx, &x265pic); |
| 609 | − return rd_idx; | |
| 626 | + return ret; | |
| 610 | 627 | } |
| 611 | − | |
| 612 | − x265pic.userData = (void*)(intptr_t)(rd_idx + 1); | |
| 613 | − | |
| 614 | − rd = &ctx->rd[rd_idx]; | |
| 615 | − rd->reordered_opaque = pic->reordered_opaque; | |
| 616 | 628 | } |
| 617 | 629 | |
| 630 | + x265pic.userData = (void*)(intptr_t)(rd_idx + 1); | |
| 631 | + | |
| 618 | 632 | if (ctx->a53_cc) { |
| 619 | 633 | void *sei_data; |
| 620 | 634 | size_t sei_size; |
| @@ -742,6 +756,12 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, · 121 unmodified lines | ||
| 742 | 756 | |
| 743 | 757 | avctx->reordered_opaque = rd->reordered_opaque; |
| 744 | 758 | |
| 759 | + if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) { | |
| 760 | + pkt->opaque = rd->frame_opaque; | |
| 761 | + pkt->opaque_ref = rd->frame_opaque_ref; | |
| 762 | + rd->frame_opaque_ref = NULL; | |
| 763 | + } | |
| 764 | + | |
| 745 | 765 | rd_release(ctx, idx); |
| 746 | 766 | } else |
| 747 | 767 | avctx->reordered_opaque = 0; |
| @@ -58,6 +58,7 @@ static const AVOption avcodec_options[] = { · 57 unmodified lines | ||
| 58 | 58 | {"loop", "use loop filter", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_LOOP_FILTER }, INT_MIN, INT_MAX, V|E, "flags"}, |
| 59 | 59 | {"qscale", "use fixed qscale", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_QSCALE }, INT_MIN, INT_MAX, 0, "flags"}, |
| 60 | 60 | {"recon_frame", "export reconstructed frames", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_RECON_FRAME}, .unit = "flags"}, |
| 61 | +{"copy_opaque", "propagate opaque values", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_COPY_OPAQUE}, .unit = "flags"}, | |
| 61 | 62 | {"pass1", "use internal 2-pass ratecontrol in first pass mode", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_PASS1 }, INT_MIN, INT_MAX, 0, "flags"}, |
| 62 | 63 | {"pass2", "use internal 2-pass ratecontrol in second pass mode", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_PASS2 }, INT_MIN, INT_MAX, 0, "flags"}, |
| 63 | 64 | {"gray", "only decode/encode grayscale", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_GRAY }, INT_MIN, INT_MAX, V|E|D, "flags"}, |
| @@ -29,7 +29,7 @@ · 28 unmodified lines | ||
| 29 | 29 | |
| 30 | 30 | #include "version_major.h" |
| 31 | 31 | |
| 32 | −#define LIBAVCODEC_VERSION_MINOR 58 | |
| 32 | +#define LIBAVCODEC_VERSION_MINOR 59 | |
| 33 | 33 | #define LIBAVCODEC_VERSION_MICRO 100 |
| 34 | 34 | |
| 35 | 35 | #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ |