@@ -1612,3 +1612,96 @@ void ff_cbs_h264_delete_sei_message(CodedBitstreamContext *ctx,
(sei->payload_count - position) * sizeof(*sei->payload));
}
}
+
+int ff_cbs_h265_add_sei_prefix_message(CodedBitstreamContext *ctx,
+ CodedBitstreamFragment *au,
+ H265RawSEIPayload *payload)
+{
+ H265RawSEI *sei = NULL;
+ int err, i;
+
+ // Find an existing SEI PREFIX NAL unit to add to.
+ for (i = 0; i < au->nb_units; i++) {
+ if (au->units[i].type == HEVC_NAL_SEI_PREFIX) {
+ sei = au->units[i].content;
+ if (sei->payload_count < H265_MAX_SEI_PAYLOADS)
+ break;
+
+ sei = NULL;
+ }
+ }
+
+ if (!sei) {
+ // Need to make a new SEI NAL unit. Insert it before the first
+ // slice data NAL unit; if no slice data, add at the end.
+ AVBufferRef *sei_ref;
+
+ sei = av_mallocz(sizeof(*sei));
+ if (!sei) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ sei->nal_unit_header.nal_unit_type = HEVC_NAL_SEI_PREFIX;
+ sei->nal_unit_header.nuh_layer_id = 0;
+ sei->nal_unit_header.nuh_temporal_id_plus1 = 1;
+
+ sei_ref = av_buffer_create((uint8_t*)sei, sizeof(*sei),
+ &cbs_h265_free_sei, NULL, 0);
+ if (!sei_ref) {
+ av_freep(&sei);
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ for (i = 0; i < au->nb_units; i++) {
+ if (au->units[i].type == HEVC_NAL_IDR_W_RADL ||
+ au->units[i].type == HEVC_NAL_IDR_N_LP)
+ break;
+ }
+
+ err = ff_cbs_insert_unit_content(ctx, au, i, HEVC_NAL_SEI_PREFIX,
+ sei, sei_ref);
+ av_buffer_unref(&sei_ref);
+ if (err < 0)
+ goto fail;
+ }
+
+ memcpy(&sei->payload[sei->payload_count], payload, sizeof(*payload));
+ ++sei->payload_count;
+
+ return 0;
+fail:
+ cbs_h265_free_sei_payload(payload);
+ return err;
+}
+
+void ff_cbs_h265_delete_sei_prefix_message(CodedBitstreamContext *ctx,
+ CodedBitstreamFragment *au,
+ CodedBitstreamUnit *nal,
+ int position)
+{
+ H265RawSEI *sei = nal->content;
+
+ av_assert0(nal->type == HEVC_NAL_SEI_PREFIX);
+ av_assert0(position >= 0 && position < sei->payload_count);
+
+ if (position == 0 && sei->payload_count == 1) {
+ // Deleting NAL unit entirely.
+ int i;
+
+ for (i = 0; i < au->nb_units; i++) {
+ if (&au->units[i] == nal)
+ break;
+ }
+
+ ff_cbs_delete_unit(ctx, au, i);
+ } else {
+ cbs_h265_free_sei_payload(&sei->payload[position]);
+
+ --sei->payload_count;
+ memmove(sei->payload + position,
+ sei->payload + position + 1,
+ (sei->payload_count - position) * sizeof(*sei->payload));
+ }
+}
@@ -22,6 +22,7 @@
#include <stddef.h>
#include <stdint.h>
+#include "cbs.h"
#include "cbs_h2645.h"
#include "hevc.h"
@@ -745,5 +746,29 @@ typedef struct CodedBitstreamH265Context {
const H265RawPPS *active_pps;
} CodedBitstreamH265Context;
+/**
+ * Add an SEI message to an access unit.
+ *
+ * On success, the payload will be owned by a unit in access_unit;
+ * on failure, the content of the payload will be freed.
+ */
+int ff_cbs_h265_add_sei_prefix_message(CodedBitstreamContext *ctx,
+ CodedBitstreamFragment *access_unit,
+ H265RawSEIPayload *payload);
+
+/**
+ * Delete an SEI message from an access unit.
+ *
+ * Deletes from nal_unit, which must be an SEI PREFIX NAL unit. If this is the
+ * last message in nal_unit, also deletes it from access_unit.
+ *
+ * Requires nal_unit to be a unit in access_unit and position to be >= 0
+ * and < the payload count of the SEI nal_unit.
+ */
+void ff_cbs_h265_delete_sei_prefix_message(CodedBitstreamContext *ctx,
+ CodedBitstreamFragment *access_unit,
+ CodedBitstreamUnit *nal_unit,
+ int position);
+
#endif /* AVCODEC_CBS_H265_H */