1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * This file is part of FFmpeg. 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 5cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 6cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 7cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 8cabdff1aSopenharmony_ci * 9cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 10cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 11cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12cabdff1aSopenharmony_ci * Lesser General Public License for more details. 13cabdff1aSopenharmony_ci * 14cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 15cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 16cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17cabdff1aSopenharmony_ci */ 18cabdff1aSopenharmony_ci 19cabdff1aSopenharmony_ci#include "cbs.h" 20cabdff1aSopenharmony_ci#include "cbs_internal.h" 21cabdff1aSopenharmony_ci#include "cbs_h264.h" 22cabdff1aSopenharmony_ci#include "cbs_h265.h" 23cabdff1aSopenharmony_ci#include "cbs_sei.h" 24cabdff1aSopenharmony_ci 25cabdff1aSopenharmony_cistatic void cbs_free_user_data_registered(void *opaque, uint8_t *data) 26cabdff1aSopenharmony_ci{ 27cabdff1aSopenharmony_ci SEIRawUserDataRegistered *udr = (SEIRawUserDataRegistered*)data; 28cabdff1aSopenharmony_ci av_buffer_unref(&udr->data_ref); 29cabdff1aSopenharmony_ci av_free(udr); 30cabdff1aSopenharmony_ci} 31cabdff1aSopenharmony_ci 32cabdff1aSopenharmony_cistatic void cbs_free_user_data_unregistered(void *opaque, uint8_t *data) 33cabdff1aSopenharmony_ci{ 34cabdff1aSopenharmony_ci SEIRawUserDataUnregistered *udu = (SEIRawUserDataUnregistered*)data; 35cabdff1aSopenharmony_ci av_buffer_unref(&udu->data_ref); 36cabdff1aSopenharmony_ci av_free(udu); 37cabdff1aSopenharmony_ci} 38cabdff1aSopenharmony_ci 39cabdff1aSopenharmony_ciint ff_cbs_sei_alloc_message_payload(SEIRawMessage *message, 40cabdff1aSopenharmony_ci const SEIMessageTypeDescriptor *desc) 41cabdff1aSopenharmony_ci{ 42cabdff1aSopenharmony_ci void (*free_func)(void*, uint8_t*); 43cabdff1aSopenharmony_ci 44cabdff1aSopenharmony_ci av_assert0(message->payload == NULL && 45cabdff1aSopenharmony_ci message->payload_ref == NULL); 46cabdff1aSopenharmony_ci message->payload_type = desc->type; 47cabdff1aSopenharmony_ci 48cabdff1aSopenharmony_ci if (desc->type == SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35) 49cabdff1aSopenharmony_ci free_func = &cbs_free_user_data_registered; 50cabdff1aSopenharmony_ci else if (desc->type == SEI_TYPE_USER_DATA_UNREGISTERED) 51cabdff1aSopenharmony_ci free_func = &cbs_free_user_data_unregistered; 52cabdff1aSopenharmony_ci else 53cabdff1aSopenharmony_ci free_func = NULL; 54cabdff1aSopenharmony_ci 55cabdff1aSopenharmony_ci if (free_func) { 56cabdff1aSopenharmony_ci message->payload = av_mallocz(desc->size); 57cabdff1aSopenharmony_ci if (!message->payload) 58cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 59cabdff1aSopenharmony_ci message->payload_ref = 60cabdff1aSopenharmony_ci av_buffer_create(message->payload, desc->size, 61cabdff1aSopenharmony_ci free_func, NULL, 0); 62cabdff1aSopenharmony_ci } else { 63cabdff1aSopenharmony_ci message->payload_ref = av_buffer_alloc(desc->size); 64cabdff1aSopenharmony_ci } 65cabdff1aSopenharmony_ci if (!message->payload_ref) { 66cabdff1aSopenharmony_ci av_freep(&message->payload); 67cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 68cabdff1aSopenharmony_ci } 69cabdff1aSopenharmony_ci message->payload = message->payload_ref->data; 70cabdff1aSopenharmony_ci 71cabdff1aSopenharmony_ci return 0; 72cabdff1aSopenharmony_ci} 73cabdff1aSopenharmony_ci 74cabdff1aSopenharmony_ciint ff_cbs_sei_list_add(SEIRawMessageList *list) 75cabdff1aSopenharmony_ci{ 76cabdff1aSopenharmony_ci void *ptr; 77cabdff1aSopenharmony_ci int old_count = list->nb_messages_allocated; 78cabdff1aSopenharmony_ci 79cabdff1aSopenharmony_ci av_assert0(list->nb_messages <= old_count); 80cabdff1aSopenharmony_ci if (list->nb_messages + 1 > old_count) { 81cabdff1aSopenharmony_ci int new_count = 2 * old_count + 1; 82cabdff1aSopenharmony_ci 83cabdff1aSopenharmony_ci ptr = av_realloc_array(list->messages, 84cabdff1aSopenharmony_ci new_count, sizeof(*list->messages)); 85cabdff1aSopenharmony_ci if (!ptr) 86cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 87cabdff1aSopenharmony_ci 88cabdff1aSopenharmony_ci list->messages = ptr; 89cabdff1aSopenharmony_ci list->nb_messages_allocated = new_count; 90cabdff1aSopenharmony_ci 91cabdff1aSopenharmony_ci // Zero the newly-added entries. 92cabdff1aSopenharmony_ci memset(list->messages + old_count, 0, 93cabdff1aSopenharmony_ci (new_count - old_count) * sizeof(*list->messages)); 94cabdff1aSopenharmony_ci } 95cabdff1aSopenharmony_ci ++list->nb_messages; 96cabdff1aSopenharmony_ci return 0; 97cabdff1aSopenharmony_ci} 98cabdff1aSopenharmony_ci 99cabdff1aSopenharmony_civoid ff_cbs_sei_free_message_list(SEIRawMessageList *list) 100cabdff1aSopenharmony_ci{ 101cabdff1aSopenharmony_ci for (int i = 0; i < list->nb_messages; i++) { 102cabdff1aSopenharmony_ci SEIRawMessage *message = &list->messages[i]; 103cabdff1aSopenharmony_ci av_buffer_unref(&message->payload_ref); 104cabdff1aSopenharmony_ci av_buffer_unref(&message->extension_data_ref); 105cabdff1aSopenharmony_ci } 106cabdff1aSopenharmony_ci av_free(list->messages); 107cabdff1aSopenharmony_ci} 108cabdff1aSopenharmony_ci 109cabdff1aSopenharmony_cistatic int cbs_sei_get_unit(CodedBitstreamContext *ctx, 110cabdff1aSopenharmony_ci CodedBitstreamFragment *au, 111cabdff1aSopenharmony_ci int prefix, 112cabdff1aSopenharmony_ci CodedBitstreamUnit **sei_unit) 113cabdff1aSopenharmony_ci{ 114cabdff1aSopenharmony_ci CodedBitstreamUnit *unit; 115cabdff1aSopenharmony_ci int sei_type, highest_vcl_type, err, i, position; 116cabdff1aSopenharmony_ci 117cabdff1aSopenharmony_ci switch (ctx->codec->codec_id) { 118cabdff1aSopenharmony_ci case AV_CODEC_ID_H264: 119cabdff1aSopenharmony_ci // (We can ignore auxiliary slices because we only have prefix 120cabdff1aSopenharmony_ci // SEI in H.264 and an auxiliary picture must always follow a 121cabdff1aSopenharmony_ci // primary picture.) 122cabdff1aSopenharmony_ci highest_vcl_type = H264_NAL_IDR_SLICE; 123cabdff1aSopenharmony_ci if (prefix) 124cabdff1aSopenharmony_ci sei_type = H264_NAL_SEI; 125cabdff1aSopenharmony_ci else 126cabdff1aSopenharmony_ci return AVERROR(EINVAL); 127cabdff1aSopenharmony_ci break; 128cabdff1aSopenharmony_ci case AV_CODEC_ID_H265: 129cabdff1aSopenharmony_ci highest_vcl_type = HEVC_NAL_RSV_VCL31; 130cabdff1aSopenharmony_ci if (prefix) 131cabdff1aSopenharmony_ci sei_type = HEVC_NAL_SEI_PREFIX; 132cabdff1aSopenharmony_ci else 133cabdff1aSopenharmony_ci sei_type = HEVC_NAL_SEI_SUFFIX; 134cabdff1aSopenharmony_ci break; 135cabdff1aSopenharmony_ci default: 136cabdff1aSopenharmony_ci return AVERROR(EINVAL); 137cabdff1aSopenharmony_ci } 138cabdff1aSopenharmony_ci 139cabdff1aSopenharmony_ci // Find an existing SEI NAL unit of the right type. 140cabdff1aSopenharmony_ci unit = NULL; 141cabdff1aSopenharmony_ci for (i = 0; i < au->nb_units; i++) { 142cabdff1aSopenharmony_ci if (au->units[i].type == sei_type) { 143cabdff1aSopenharmony_ci unit = &au->units[i]; 144cabdff1aSopenharmony_ci break; 145cabdff1aSopenharmony_ci } 146cabdff1aSopenharmony_ci } 147cabdff1aSopenharmony_ci 148cabdff1aSopenharmony_ci if (unit) { 149cabdff1aSopenharmony_ci *sei_unit = unit; 150cabdff1aSopenharmony_ci return 0; 151cabdff1aSopenharmony_ci } 152cabdff1aSopenharmony_ci 153cabdff1aSopenharmony_ci // Need to add a new SEI NAL unit ... 154cabdff1aSopenharmony_ci if (prefix) { 155cabdff1aSopenharmony_ci // ... before the first VCL NAL unit. 156cabdff1aSopenharmony_ci for (i = 0; i < au->nb_units; i++) { 157cabdff1aSopenharmony_ci if (au->units[i].type < highest_vcl_type) 158cabdff1aSopenharmony_ci break; 159cabdff1aSopenharmony_ci } 160cabdff1aSopenharmony_ci position = i; 161cabdff1aSopenharmony_ci } else { 162cabdff1aSopenharmony_ci // ... after the last VCL NAL unit. 163cabdff1aSopenharmony_ci for (i = au->nb_units - 1; i >= 0; i--) { 164cabdff1aSopenharmony_ci if (au->units[i].type < highest_vcl_type) 165cabdff1aSopenharmony_ci break; 166cabdff1aSopenharmony_ci } 167cabdff1aSopenharmony_ci if (i < 0) { 168cabdff1aSopenharmony_ci // No VCL units; just put it at the end. 169cabdff1aSopenharmony_ci position = au->nb_units; 170cabdff1aSopenharmony_ci } else { 171cabdff1aSopenharmony_ci position = i + 1; 172cabdff1aSopenharmony_ci } 173cabdff1aSopenharmony_ci } 174cabdff1aSopenharmony_ci 175cabdff1aSopenharmony_ci err = ff_cbs_insert_unit_content(au, position, sei_type, 176cabdff1aSopenharmony_ci NULL, NULL); 177cabdff1aSopenharmony_ci if (err < 0) 178cabdff1aSopenharmony_ci return err; 179cabdff1aSopenharmony_ci unit = &au->units[position]; 180cabdff1aSopenharmony_ci unit->type = sei_type; 181cabdff1aSopenharmony_ci 182cabdff1aSopenharmony_ci err = ff_cbs_alloc_unit_content2(ctx, unit); 183cabdff1aSopenharmony_ci if (err < 0) 184cabdff1aSopenharmony_ci return err; 185cabdff1aSopenharmony_ci 186cabdff1aSopenharmony_ci switch (ctx->codec->codec_id) { 187cabdff1aSopenharmony_ci case AV_CODEC_ID_H264: 188cabdff1aSopenharmony_ci { 189cabdff1aSopenharmony_ci H264RawSEI sei = { 190cabdff1aSopenharmony_ci .nal_unit_header = { 191cabdff1aSopenharmony_ci .nal_ref_idc = 0, 192cabdff1aSopenharmony_ci .nal_unit_type = sei_type, 193cabdff1aSopenharmony_ci }, 194cabdff1aSopenharmony_ci }; 195cabdff1aSopenharmony_ci memcpy(unit->content, &sei, sizeof(sei)); 196cabdff1aSopenharmony_ci } 197cabdff1aSopenharmony_ci break; 198cabdff1aSopenharmony_ci case AV_CODEC_ID_H265: 199cabdff1aSopenharmony_ci { 200cabdff1aSopenharmony_ci H265RawSEI sei = { 201cabdff1aSopenharmony_ci .nal_unit_header = { 202cabdff1aSopenharmony_ci .nal_unit_type = sei_type, 203cabdff1aSopenharmony_ci .nuh_layer_id = 0, 204cabdff1aSopenharmony_ci .nuh_temporal_id_plus1 = 1, 205cabdff1aSopenharmony_ci }, 206cabdff1aSopenharmony_ci }; 207cabdff1aSopenharmony_ci memcpy(unit->content, &sei, sizeof(sei)); 208cabdff1aSopenharmony_ci } 209cabdff1aSopenharmony_ci break; 210cabdff1aSopenharmony_ci default: 211cabdff1aSopenharmony_ci av_assert0(0); 212cabdff1aSopenharmony_ci } 213cabdff1aSopenharmony_ci 214cabdff1aSopenharmony_ci *sei_unit = unit; 215cabdff1aSopenharmony_ci return 0; 216cabdff1aSopenharmony_ci} 217cabdff1aSopenharmony_ci 218cabdff1aSopenharmony_cistatic int cbs_sei_get_message_list(CodedBitstreamContext *ctx, 219cabdff1aSopenharmony_ci CodedBitstreamUnit *unit, 220cabdff1aSopenharmony_ci SEIRawMessageList **list) 221cabdff1aSopenharmony_ci{ 222cabdff1aSopenharmony_ci switch (ctx->codec->codec_id) { 223cabdff1aSopenharmony_ci case AV_CODEC_ID_H264: 224cabdff1aSopenharmony_ci { 225cabdff1aSopenharmony_ci H264RawSEI *sei = unit->content; 226cabdff1aSopenharmony_ci if (unit->type != H264_NAL_SEI) 227cabdff1aSopenharmony_ci return AVERROR(EINVAL); 228cabdff1aSopenharmony_ci *list = &sei->message_list; 229cabdff1aSopenharmony_ci } 230cabdff1aSopenharmony_ci break; 231cabdff1aSopenharmony_ci case AV_CODEC_ID_H265: 232cabdff1aSopenharmony_ci { 233cabdff1aSopenharmony_ci H265RawSEI *sei = unit->content; 234cabdff1aSopenharmony_ci if (unit->type != HEVC_NAL_SEI_PREFIX && 235cabdff1aSopenharmony_ci unit->type != HEVC_NAL_SEI_SUFFIX) 236cabdff1aSopenharmony_ci return AVERROR(EINVAL); 237cabdff1aSopenharmony_ci *list = &sei->message_list; 238cabdff1aSopenharmony_ci } 239cabdff1aSopenharmony_ci break; 240cabdff1aSopenharmony_ci default: 241cabdff1aSopenharmony_ci return AVERROR(EINVAL); 242cabdff1aSopenharmony_ci } 243cabdff1aSopenharmony_ci 244cabdff1aSopenharmony_ci return 0; 245cabdff1aSopenharmony_ci} 246cabdff1aSopenharmony_ci 247cabdff1aSopenharmony_ciint ff_cbs_sei_add_message(CodedBitstreamContext *ctx, 248cabdff1aSopenharmony_ci CodedBitstreamFragment *au, 249cabdff1aSopenharmony_ci int prefix, 250cabdff1aSopenharmony_ci uint32_t payload_type, 251cabdff1aSopenharmony_ci void *payload_data, 252cabdff1aSopenharmony_ci AVBufferRef *payload_buf) 253cabdff1aSopenharmony_ci{ 254cabdff1aSopenharmony_ci const SEIMessageTypeDescriptor *desc; 255cabdff1aSopenharmony_ci CodedBitstreamUnit *unit; 256cabdff1aSopenharmony_ci SEIRawMessageList *list; 257cabdff1aSopenharmony_ci SEIRawMessage *message; 258cabdff1aSopenharmony_ci AVBufferRef *payload_ref; 259cabdff1aSopenharmony_ci int err; 260cabdff1aSopenharmony_ci 261cabdff1aSopenharmony_ci desc = ff_cbs_sei_find_type(ctx, payload_type); 262cabdff1aSopenharmony_ci if (!desc) 263cabdff1aSopenharmony_ci return AVERROR(EINVAL); 264cabdff1aSopenharmony_ci 265cabdff1aSopenharmony_ci // Find an existing SEI unit or make a new one to add to. 266cabdff1aSopenharmony_ci err = cbs_sei_get_unit(ctx, au, prefix, &unit); 267cabdff1aSopenharmony_ci if (err < 0) 268cabdff1aSopenharmony_ci return err; 269cabdff1aSopenharmony_ci 270cabdff1aSopenharmony_ci // Find the message list inside the codec-dependent unit. 271cabdff1aSopenharmony_ci err = cbs_sei_get_message_list(ctx, unit, &list); 272cabdff1aSopenharmony_ci if (err < 0) 273cabdff1aSopenharmony_ci return err; 274cabdff1aSopenharmony_ci 275cabdff1aSopenharmony_ci // Add a new message to the message list. 276cabdff1aSopenharmony_ci err = ff_cbs_sei_list_add(list); 277cabdff1aSopenharmony_ci if (err < 0) 278cabdff1aSopenharmony_ci return err; 279cabdff1aSopenharmony_ci 280cabdff1aSopenharmony_ci if (payload_buf) { 281cabdff1aSopenharmony_ci payload_ref = av_buffer_ref(payload_buf); 282cabdff1aSopenharmony_ci if (!payload_ref) 283cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 284cabdff1aSopenharmony_ci } else { 285cabdff1aSopenharmony_ci payload_ref = NULL; 286cabdff1aSopenharmony_ci } 287cabdff1aSopenharmony_ci 288cabdff1aSopenharmony_ci message = &list->messages[list->nb_messages - 1]; 289cabdff1aSopenharmony_ci 290cabdff1aSopenharmony_ci message->payload_type = payload_type; 291cabdff1aSopenharmony_ci message->payload = payload_data; 292cabdff1aSopenharmony_ci message->payload_ref = payload_ref; 293cabdff1aSopenharmony_ci 294cabdff1aSopenharmony_ci return 0; 295cabdff1aSopenharmony_ci} 296cabdff1aSopenharmony_ci 297cabdff1aSopenharmony_ciint ff_cbs_sei_find_message(CodedBitstreamContext *ctx, 298cabdff1aSopenharmony_ci CodedBitstreamFragment *au, 299cabdff1aSopenharmony_ci uint32_t payload_type, 300cabdff1aSopenharmony_ci SEIRawMessage **iter) 301cabdff1aSopenharmony_ci{ 302cabdff1aSopenharmony_ci int err, i, j, found; 303cabdff1aSopenharmony_ci 304cabdff1aSopenharmony_ci found = 0; 305cabdff1aSopenharmony_ci for (i = 0; i < au->nb_units; i++) { 306cabdff1aSopenharmony_ci CodedBitstreamUnit *unit = &au->units[i]; 307cabdff1aSopenharmony_ci SEIRawMessageList *list; 308cabdff1aSopenharmony_ci 309cabdff1aSopenharmony_ci err = cbs_sei_get_message_list(ctx, unit, &list); 310cabdff1aSopenharmony_ci if (err < 0) 311cabdff1aSopenharmony_ci continue; 312cabdff1aSopenharmony_ci 313cabdff1aSopenharmony_ci for (j = 0; j < list->nb_messages; j++) { 314cabdff1aSopenharmony_ci SEIRawMessage *message = &list->messages[j]; 315cabdff1aSopenharmony_ci 316cabdff1aSopenharmony_ci if (message->payload_type == payload_type) { 317cabdff1aSopenharmony_ci if (!*iter || found) { 318cabdff1aSopenharmony_ci *iter = message; 319cabdff1aSopenharmony_ci return 0; 320cabdff1aSopenharmony_ci } 321cabdff1aSopenharmony_ci if (message == *iter) 322cabdff1aSopenharmony_ci found = 1; 323cabdff1aSopenharmony_ci } 324cabdff1aSopenharmony_ci } 325cabdff1aSopenharmony_ci } 326cabdff1aSopenharmony_ci 327cabdff1aSopenharmony_ci return AVERROR(ENOENT); 328cabdff1aSopenharmony_ci} 329cabdff1aSopenharmony_ci 330cabdff1aSopenharmony_cistatic void cbs_sei_delete_message(SEIRawMessageList *list, 331cabdff1aSopenharmony_ci int position) 332cabdff1aSopenharmony_ci{ 333cabdff1aSopenharmony_ci SEIRawMessage *message; 334cabdff1aSopenharmony_ci 335cabdff1aSopenharmony_ci av_assert0(0 <= position && position < list->nb_messages); 336cabdff1aSopenharmony_ci 337cabdff1aSopenharmony_ci message = &list->messages[position]; 338cabdff1aSopenharmony_ci av_buffer_unref(&message->payload_ref); 339cabdff1aSopenharmony_ci av_buffer_unref(&message->extension_data_ref); 340cabdff1aSopenharmony_ci 341cabdff1aSopenharmony_ci --list->nb_messages; 342cabdff1aSopenharmony_ci 343cabdff1aSopenharmony_ci if (list->nb_messages > 0) { 344cabdff1aSopenharmony_ci memmove(list->messages + position, 345cabdff1aSopenharmony_ci list->messages + position + 1, 346cabdff1aSopenharmony_ci (list->nb_messages - position) * sizeof(*list->messages)); 347cabdff1aSopenharmony_ci } 348cabdff1aSopenharmony_ci} 349cabdff1aSopenharmony_ci 350cabdff1aSopenharmony_civoid ff_cbs_sei_delete_message_type(CodedBitstreamContext *ctx, 351cabdff1aSopenharmony_ci CodedBitstreamFragment *au, 352cabdff1aSopenharmony_ci uint32_t payload_type) 353cabdff1aSopenharmony_ci{ 354cabdff1aSopenharmony_ci int err, i, j; 355cabdff1aSopenharmony_ci 356cabdff1aSopenharmony_ci for (i = 0; i < au->nb_units; i++) { 357cabdff1aSopenharmony_ci CodedBitstreamUnit *unit = &au->units[i]; 358cabdff1aSopenharmony_ci SEIRawMessageList *list; 359cabdff1aSopenharmony_ci 360cabdff1aSopenharmony_ci err = cbs_sei_get_message_list(ctx, unit, &list); 361cabdff1aSopenharmony_ci if (err < 0) 362cabdff1aSopenharmony_ci continue; 363cabdff1aSopenharmony_ci 364cabdff1aSopenharmony_ci for (j = list->nb_messages - 1; j >= 0; j--) { 365cabdff1aSopenharmony_ci if (list->messages[j].payload_type == payload_type) 366cabdff1aSopenharmony_ci cbs_sei_delete_message(list, j); 367cabdff1aSopenharmony_ci } 368cabdff1aSopenharmony_ci } 369cabdff1aSopenharmony_ci} 370