]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/av1_metadata_bsf.c
avcodec.h: split AVCodec API into its own header
[ffmpeg] / libavcodec / av1_metadata_bsf.c
index ed2f018fb69b5801ac704bae3d6fd5b4aa1ed74b..ee1a63c1ecf378d0f776f6b8f1ae1d705058eada 100644 (file)
 #include "libavutil/opt.h"
 
 #include "bsf.h"
+#include "bsf_internal.h"
 #include "cbs.h"
 #include "cbs_av1.h"
 
+enum {
+    PASS,
+    INSERT,
+    REMOVE,
+};
+
 typedef struct AV1MetadataContext {
     const AVClass *class;
 
     CodedBitstreamContext *cbc;
     CodedBitstreamFragment access_unit;
 
+    int td;
+
     int color_primaries;
     int transfer_characteristics;
     int matrix_coefficients;
@@ -38,6 +47,8 @@ typedef struct AV1MetadataContext {
 
     AVRational tick_rate;
     int num_ticks_per_picture;
+
+    int delete_padding;
 } AV1MetadataContext;
 
 
@@ -51,12 +62,7 @@ static int av1_metadata_update_sequence_header(AVBSFContext *bsf,
     if (ctx->color_primaries >= 0          ||
         ctx->transfer_characteristics >= 0 ||
         ctx->matrix_coefficients >= 0) {
-        if (!clc->color_description_present_flag) {
-            clc->color_description_present_flag = 1;
-            clc->color_primaries          = AVCOL_PRI_UNSPECIFIED;
-            clc->transfer_characteristics = AVCOL_TRC_UNSPECIFIED;
-            clc->matrix_coefficients      = AVCOL_SPC_UNSPECIFIED;
-        }
+        clc->color_description_present_flag = 1;
 
         if (ctx->color_primaries >= 0)
             clc->color_primaries = ctx->color_primaries;
@@ -78,13 +84,9 @@ static int av1_metadata_update_sequence_header(AVBSFContext *bsf,
     }
 
     if (ctx->chroma_sample_position >= 0) {
-        if (clc->mono_chrome) {
-            av_log(bsf, AV_LOG_WARNING, "Warning: chroma_sample_position "
-                   "is not meaningful for monochrome streams.\n");
-        } else if (clc->subsampling_x == 0 &&
-                   clc->subsampling_y == 0) {
+        if (clc->mono_chrome || !clc->subsampling_x || !clc->subsampling_y) {
             av_log(bsf, AV_LOG_WARNING, "Warning: chroma_sample_position "
-                   "is not meaningful for non-chroma-subsampled streams.\n");
+                   "can only be set for 4:2:0 streams.\n");
         } else {
             clc->chroma_sample_position = ctx->chroma_sample_position;
         }
@@ -110,24 +112,77 @@ static int av1_metadata_update_sequence_header(AVBSFContext *bsf,
     return 0;
 }
 
-static int av1_metadata_filter(AVBSFContext *bsf, AVPacket *out)
+static int av1_metadata_update_side_data(AVBSFContext *bsf, AVPacket *pkt)
 {
     AV1MetadataContext *ctx = bsf->priv_data;
-    AVPacket *in = NULL;
     CodedBitstreamFragment *frag = &ctx->access_unit;
-    AV1RawOBU *obu;
+    uint8_t *side_data;
+    int side_data_size;
     int err, i;
 
-    err = ff_bsf_get_packet(bsf, &in);
+    side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
+                                        &side_data_size);
+    if (!side_data_size)
+        return 0;
+
+    err = ff_cbs_read(ctx->cbc, frag, side_data, side_data_size);
+    if (err < 0) {
+        av_log(bsf, AV_LOG_ERROR, "Failed to read extradata from packet side data.\n");
+        return err;
+    }
+
+    for (i = 0; i < frag->nb_units; i++) {
+        if (frag->units[i].type == AV1_OBU_SEQUENCE_HEADER) {
+            AV1RawOBU *obu = frag->units[i].content;
+            err = av1_metadata_update_sequence_header(bsf, &obu->obu.sequence_header);
+            if (err < 0)
+                return err;
+        }
+    }
+
+    err = ff_cbs_write_fragment_data(ctx->cbc, frag);
+    if (err < 0) {
+        av_log(bsf, AV_LOG_ERROR, "Failed to write extradata into packet side data.\n");
+        return err;
+    }
+
+    side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, frag->data_size);
+    if (!side_data)
+        return AVERROR(ENOMEM);
+    memcpy(side_data, frag->data, frag->data_size);
+
+    ff_cbs_fragment_reset(ctx->cbc, frag);
+
+    return 0;
+}
+
+static int av1_metadata_filter(AVBSFContext *bsf, AVPacket *pkt)
+{
+    AV1MetadataContext *ctx = bsf->priv_data;
+    CodedBitstreamFragment *frag = &ctx->access_unit;
+    AV1RawOBU td, *obu;
+    int err, i;
+
+    err = ff_bsf_get_packet_ref(bsf, pkt);
     if (err < 0)
         return err;
 
-    err = ff_cbs_read_packet(ctx->cbc, frag, in);
+    err = av1_metadata_update_side_data(bsf, pkt);
+    if (err < 0)
+        goto fail;
+
+    err = ff_cbs_read_packet(ctx->cbc, frag, pkt);
     if (err < 0) {
         av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n");
         goto fail;
     }
 
+    if (frag->nb_units == 0) {
+        av_log(bsf, AV_LOG_ERROR, "No OBU in packet.\n");
+        err = AVERROR_INVALIDDATA;
+        goto fail;
+    }
+
     for (i = 0; i < frag->nb_units; i++) {
         if (frag->units[i].type == AV1_OBU_SEQUENCE_HEADER) {
             obu = frag->units[i].content;
@@ -137,23 +192,42 @@ static int av1_metadata_filter(AVBSFContext *bsf, AVPacket *out)
         }
     }
 
-    err = ff_cbs_write_packet(ctx->cbc, out, frag);
+    // If a Temporal Delimiter is present, it must be the first OBU.
+    if (frag->units[0].type == AV1_OBU_TEMPORAL_DELIMITER) {
+        if (ctx->td == REMOVE)
+            ff_cbs_delete_unit(ctx->cbc, frag, 0);
+    } else if (ctx->td == INSERT) {
+        td = (AV1RawOBU) {
+            .header.obu_type = AV1_OBU_TEMPORAL_DELIMITER,
+        };
+
+        err = ff_cbs_insert_unit_content(ctx->cbc, frag, 0, AV1_OBU_TEMPORAL_DELIMITER,
+                                         &td, NULL);
+        if (err < 0) {
+            av_log(bsf, AV_LOG_ERROR, "Failed to insert Temporal Delimiter.\n");
+            goto fail;
+        }
+    }
+
+    if (ctx->delete_padding) {
+        for (i = frag->nb_units - 1; i >= 0; i--) {
+            if (frag->units[i].type == AV1_OBU_PADDING)
+                ff_cbs_delete_unit(ctx->cbc, frag, i);
+        }
+    }
+
+    err = ff_cbs_write_packet(ctx->cbc, pkt, frag);
     if (err < 0) {
         av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n");
         goto fail;
     }
 
-    err = av_packet_copy_props(out, in);
-    if (err < 0)
-        goto fail;
-
     err = 0;
 fail:
-    ff_cbs_fragment_uninit(ctx->cbc, frag);
+    ff_cbs_fragment_reset(ctx->cbc, frag);
 
     if (err < 0)
-        av_packet_unref(out);
-    av_packet_free(&in);
+        av_packet_unref(pkt);
 
     return err;
 }
@@ -194,19 +268,31 @@ static int av1_metadata_init(AVBSFContext *bsf)
 
     err = 0;
 fail:
-    ff_cbs_fragment_uninit(ctx->cbc, frag);
+    ff_cbs_fragment_reset(ctx->cbc, frag);
     return err;
 }
 
 static void av1_metadata_close(AVBSFContext *bsf)
 {
     AV1MetadataContext *ctx = bsf->priv_data;
+
+    ff_cbs_fragment_free(ctx->cbc, &ctx->access_unit);
     ff_cbs_close(&ctx->cbc);
 }
 
 #define OFFSET(x) offsetof(AV1MetadataContext, x)
 #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM)
 static const AVOption av1_metadata_options[] = {
+    { "td", "Temporal Delimiter OBU",
+        OFFSET(td), AV_OPT_TYPE_INT,
+        { .i64 = PASS }, PASS, REMOVE, FLAGS, "td" },
+    { "pass",   NULL, 0, AV_OPT_TYPE_CONST,
+        { .i64 = PASS   }, .flags = FLAGS, .unit = "td" },
+    { "insert", NULL, 0, AV_OPT_TYPE_CONST,
+        { .i64 = INSERT }, .flags = FLAGS, .unit = "td" },
+    { "remove", NULL, 0, AV_OPT_TYPE_CONST,
+        { .i64 = REMOVE }, .flags = FLAGS, .unit = "td" },
+
     { "color_primaries", "Set color primaries (section 6.4.2)",
         OFFSET(color_primaries), AV_OPT_TYPE_INT,
         { .i64 = -1 }, -1, 255, FLAGS },
@@ -242,6 +328,10 @@ static const AVOption av1_metadata_options[] = {
         OFFSET(num_ticks_per_picture), AV_OPT_TYPE_INT,
         { .i64 = -1 }, -1, INT_MAX, FLAGS },
 
+    { "delete_padding", "Delete all Padding OBUs",
+        OFFSET(delete_padding), AV_OPT_TYPE_BOOL,
+        { .i64 = 0 }, 0, 1, FLAGS},
+
     { NULL }
 };