History

lavc: add a codec flag for propagating opaque from frames to packets

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.

Anton Khirnov committed 4 years ago

Commit 5c0348f1 parent d0c8ca97 files · +98 −12Browse files

Unified · Split

7 files
  1. doc/APIchanges +3 −0
  2. libavcodec/avcodec.h +26 −0
  3. libavcodec/encode.c +7 −0
  4. libavcodec/libx264.c +29 −0
  5. libavcodec/libx265.c +31 −11
  6. libavcodec/options_table.h +1 −0
  7. libavcodec/version.h +1 −1
doc/APIchanges+3−0
@@ -14,6 +14,9 @@ libavutil: 2021-04-27 · 13 unmodified lines
14 14
15API changes, most recent first:15API changes, most recent first:
16 16
172023-01-xx - xxxxxxxxxx - lavc 59.59.100 - avcodec.h
18 Add AV_CODEC_FLAG_COPY_OPAQUE.
19
172023-01-13 - xxxxxxxxxx - lavu 57.44.100 - ambient_viewing_environment.h frame.h202023-01-13 - xxxxxxxxxx - lavu 57.44.100 - ambient_viewing_environment.h frame.h
18 Adds a new structure for holding H.274 Ambient Viewing Environment metadata,21 Adds a new structure for holding H.274 Ambient Viewing Environment metadata,
19 AVAmbientViewingEnvironment.22 AVAmbientViewingEnvironment.
libavcodec/avcodec.h+26−0
@@ -241,6 +241,32 @@ typedef struct RcOverride{ · 240 unmodified lines
241 * @ref AV_CODEC_CAP_ENCODER_RECON_FRAME capability.241 * @ref AV_CODEC_CAP_ENCODER_RECON_FRAME capability.
242 */242 */
243#define AV_CODEC_FLAG_RECON_FRAME (1 << 6)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 * Use internal 2pass ratecontrol in first pass mode.271 * Use internal 2pass ratecontrol in first pass mode.
246 */272 */
libavcodec/encode.c+7−0
@@ -636,6 +636,13 @@ int ff_encode_preinit(AVCodecContext *avctx) · 635 unmodified lines
636 return AVERROR(EINVAL);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 switch (avctx->codec_type) {646 switch (avctx->codec_type) {
640 case AVMEDIA_TYPE_VIDEO: ret = encode_preinit_video(avctx); break;647 case AVMEDIA_TYPE_VIDEO: ret = encode_preinit_video(avctx); break;
641 case AVMEDIA_TYPE_AUDIO: ret = encode_preinit_audio(avctx); break;648 case AVMEDIA_TYPE_AUDIO: ret = encode_preinit_audio(avctx); break;
libavcodec/libx264.c+29−0
@@ -21,6 +21,7 @@ · 20 unmodified lines
21 21
22#include "config_components.h"22#include "config_components.h"
23 23
24#include "libavutil/buffer.h"
24#include "libavutil/eval.h"25#include "libavutil/eval.h"
25#include "libavutil/internal.h"26#include "libavutil/internal.h"
26#include "libavutil/opt.h"27#include "libavutil/opt.h"
@@ -51,6 +52,9 @@ · 24 unmodified lines
51typedef struct X264Opaque {52typedef struct X264Opaque {
52 int64_t reordered_opaque;53 int64_t reordered_opaque;
53 int64_t wallclock;54 int64_t wallclock;
55
56 void *frame_opaque;
57 AVBufferRef *frame_opaque_ref;
54} X264Opaque;58} X264Opaque;
55 59
56typedef struct X264Context {60typedef struct X264Context {
@@ -133,6 +137,11 @@ static void X264_log(void *p, int level, const char *fmt, va_list args) · 76 unmodified lines
133 av_vlog(p, level_map[level], fmt, args);137 av_vlog(p, level_map[level], fmt, args);
134}138}
135 139
140static void opaque_uninit(X264Opaque *o)
141{
142 av_buffer_unref(&o->frame_opaque_ref);
143 memset(o, 0, sizeof(*o));
144}
136 145
137static int encode_nals(AVCodecContext *ctx, AVPacket *pkt,146static int encode_nals(AVCodecContext *ctx, AVPacket *pkt,
138 const x264_nal_t *nals, int nnal)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 pic->i_pts = frame->pts;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 opaque->reordered_opaque = frame->reordered_opaque;461 opaque->reordered_opaque = frame->reordered_opaque;
444 opaque->wallclock = wallclock;462 opaque->wallclock = wallclock;
445 if (ctx->export_side_data & AV_CODEC_EXPORT_DATA_PRFT)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 out_opaque < &x4->reordered_opaque[x4->nb_reordered_opaque]) {612 out_opaque < &x4->reordered_opaque[x4->nb_reordered_opaque]) {
595 ctx->reordered_opaque = out_opaque->reordered_opaque;613 ctx->reordered_opaque = out_opaque->reordered_opaque;
596 wallclock = out_opaque->wallclock;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 } else {623 } else {
598 // Unexpected opaque pointer on picture output624 // Unexpected opaque pointer on picture output
599 av_log(ctx, AV_LOG_ERROR, "Unexpected opaque pointer; "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 X264Context *x4 = avctx->priv_data;660 X264Context *x4 = avctx->priv_data;
635 661
636 av_freep(&x4->sei);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 av_freep(&x4->reordered_opaque);666 av_freep(&x4->reordered_opaque);
638 667
639#if X264_BUILD >= 161668#if X264_BUILD >= 161
libavcodec/libx265.c+31−11
@@ -28,6 +28,7 @@ · 27 unmodified lines
28#include <float.h>28#include <float.h>
29 29
30#include "libavutil/avassert.h"30#include "libavutil/avassert.h"
31#include "libavutil/buffer.h"
31#include "libavutil/internal.h"32#include "libavutil/internal.h"
32#include "libavutil/common.h"33#include "libavutil/common.h"
33#include "libavutil/opt.h"34#include "libavutil/opt.h"
@@ -43,6 +44,9 @@ · 9 unmodified lines
43typedef struct ReorderedData {44typedef struct ReorderedData {
44 int64_t reordered_opaque;45 int64_t reordered_opaque;
45 46
47 void *frame_opaque;
48 AVBufferRef *frame_opaque_ref;
49
46 int in_use;50 int in_use;
47} ReorderedData;51} ReorderedData;
48 52
@@ -121,7 +125,7 @@ static int rd_get(libx265Context *ctx) · 72 unmodified lines
121static void rd_release(libx265Context *ctx, int idx)125static void rd_release(libx265Context *ctx, int idx)
122{126{
123 av_assert0(idx >= 0 && idx < ctx->nb_rd);127 av_assert0(idx >= 0 && idx < ctx->nb_rd);
124 128 av_buffer_unref(&ctx->rd[idx].frame_opaque_ref);
125 memset(&ctx->rd[idx], 0, sizeof(ctx->rd[idx]));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 ctx->api->param_free(ctx->params);136 ctx->api->param_free(ctx->params);
133 av_freep(&ctx->sei_data);137 av_freep(&ctx->sei_data);
134 138
139 for (int i = 0; i < ctx->nb_rd; i++)
140 rd_release(ctx, i);
135 av_freep(&ctx->rd);141 av_freep(&ctx->rd);
136 142
137 if (ctx->encoder)143 if (ctx->encoder)
@@ -582,6 +588,9 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, · 444 unmodified lines
582 sei->numPayloads = 0;588 sei->numPayloads = 0;
583 589
584 if (pic) {590 if (pic) {
591 ReorderedData *rd;
592 int rd_idx;
593
585 for (i = 0; i < 3; i++) {594 for (i = 0; i < 3; i++) {
586 x265pic.planes[i] = pic->data[i];595 x265pic.planes[i] = pic->data[i];
587 x265pic.stride[i] = pic->linesize[i];596 x265pic.stride[i] = pic->linesize[i];
@@ -600,21 +609,26 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, · 12 unmodified lines
600 if (ret < 0)609 if (ret < 0)
601 return ret;610 return ret;
602 611
603 if (pic->reordered_opaque) {612 rd_idx = rd_get(ctx);
604 ReorderedData *rd;613 if (rd_idx < 0) {
605 int rd_idx = rd_get(ctx);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 free_picture(ctx, &x265pic);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 if (ctx->a53_cc) {632 if (ctx->a53_cc) {
619 void *sei_data;633 void *sei_data;
620 size_t sei_size;634 size_t sei_size;
@@ -742,6 +756,12 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, · 121 unmodified lines
742 756
743 avctx->reordered_opaque = rd->reordered_opaque;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 rd_release(ctx, idx);765 rd_release(ctx, idx);
746 } else766 } else
747 avctx->reordered_opaque = 0;767 avctx->reordered_opaque = 0;
libavcodec/options_table.h+1−0
@@ -58,6 +58,7 @@ static const AVOption avcodec_options[] = { · 57 unmodified lines
58{"loop", "use loop filter", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_LOOP_FILTER }, INT_MIN, INT_MAX, V|E, "flags"},58{"loop", "use loop filter", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_LOOP_FILTER }, INT_MIN, INT_MAX, V|E, "flags"},
59{"qscale", "use fixed qscale", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_QSCALE }, INT_MIN, INT_MAX, 0, "flags"},59{"qscale", "use fixed qscale", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_QSCALE }, INT_MIN, INT_MAX, 0, "flags"},
60{"recon_frame", "export reconstructed frames", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_RECON_FRAME}, .unit = "flags"},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{"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{"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{"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{"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{"gray", "only decode/encode grayscale", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_GRAY }, INT_MIN, INT_MAX, V|E|D, "flags"},64{"gray", "only decode/encode grayscale", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_GRAY }, INT_MIN, INT_MAX, V|E|D, "flags"},
libavcodec/version.h+1−1
@@ -29,7 +29,7 @@ · 28 unmodified lines
29 29
30#include "version_major.h"30#include "version_major.h"
31 31
32#define LIBAVCODEC_VERSION_MINOR 5832#define LIBAVCODEC_VERSION_MINOR 59
33#define LIBAVCODEC_VERSION_MICRO 10033#define LIBAVCODEC_VERSION_MICRO 100
34 34
35#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \35#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t