X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fcbs_h2645.c;h=ab33cdb69bfb6b9fbbb2c05a67f22f5f8a83ef81;hb=755e618399264d57a64a21115e2bf067b73492e7;hp=2f96e4f20eb5d4c39cf84e21259c67a543bf0abc;hpb=87faeb1e685eedc49d9cb6de14bab1cfc88ab655;p=ffmpeg diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c index 2f96e4f20eb..ab33cdb69bf 100644 --- a/libavcodec/cbs_h2645.c +++ b/libavcodec/cbs_h2645.c @@ -29,10 +29,12 @@ #include "h264_sei.h" #include "h2645_parse.h" #include "hevc.h" +#include "hevc_sei.h" static int cbs_read_ue_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, - const char *name, uint32_t *write_to, + const char *name, const int *subscripts, + uint32_t *write_to, uint32_t range_min, uint32_t range_max) { uint32_t value; @@ -68,7 +70,8 @@ static int cbs_read_ue_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, --value; if (ctx->trace_enable) - ff_cbs_trace_syntax_element(ctx, position, name, bits, value); + ff_cbs_trace_syntax_element(ctx, position, name, subscripts, + bits, value); if (value < range_min || value > range_max) { av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " @@ -82,7 +85,8 @@ static int cbs_read_ue_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, } static int cbs_read_se_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, - const char *name, int32_t *write_to, + const char *name, const int *subscripts, + int32_t *write_to, int32_t range_min, int32_t range_max) { int32_t value; @@ -122,7 +126,8 @@ static int cbs_read_se_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, value = v / 2; if (ctx->trace_enable) - ff_cbs_trace_syntax_element(ctx, position, name, bits, value); + ff_cbs_trace_syntax_element(ctx, position, name, subscripts, + bits, value); if (value < range_min || value > range_max) { av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " @@ -136,7 +141,8 @@ static int cbs_read_se_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, } static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, - const char *name, uint32_t value, + const char *name, const int *subscripts, + uint32_t value, uint32_t range_min, uint32_t range_max) { int len; @@ -164,7 +170,8 @@ static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, bits[len + i + 1] = (value + 1) >> (len - i - 1) & 1 ? '1' : '0'; bits[len + len + 1] = 0; - ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), name, bits, value); + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), + name, subscripts, bits, value); } put_bits(pbc, len, 0); @@ -177,7 +184,8 @@ static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, } static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, - const char *name, int32_t value, + const char *name, const int *subscripts, + int32_t value, int32_t range_min, int32_t range_max) { int len; @@ -213,7 +221,8 @@ static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, bits[len + i + 1] = (uvalue + 1) >> (len - i - 1) & 1 ? '1' : '0'; bits[len + len + 1] = 0; - ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), name, bits, value); + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), + name, subscripts, bits, value); } put_bits(pbc, len, 0); @@ -239,39 +248,58 @@ static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, #define FUNC_H264(rw, name) FUNC_NAME(rw, h264, name) #define FUNC_H265(rw, name) FUNC_NAME(rw, h265, name) +#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL) + +#define u(width, name, range_min, range_max) \ + xu(width, name, current->name, range_min, range_max, 0) +#define flag(name) u(1, name, 0, 1) +#define ue(name, range_min, range_max) \ + xue(name, current->name, range_min, range_max, 0) +#define se(name, range_min, range_max) \ + xse(name, current->name, range_min, range_max, 0) + +#define us(width, name, range_min, range_max, subs, ...) \ + xu(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define flags(name, subs, ...) \ + xu(1, name, current->name, 0, 1, subs, __VA_ARGS__) +#define ues(name, range_min, range_max, subs, ...) \ + xue(name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define ses(name, range_min, range_max, subs, ...) \ + xse(name, current->name, range_min, range_max, subs, __VA_ARGS__) + +#define fixed(width, name, value) do { \ + av_unused uint32_t fixed_value = value; \ + xu(width, name, fixed_value, value, value, 0); \ + } while (0) + #define READ #define READWRITE read #define RWContext GetBitContext -#define xu(width, name, var, range_min, range_max) do { \ +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ uint32_t value = range_min; \ CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ &value, range_min, range_max)); \ var = value; \ } while (0) -#define xue(name, var, range_min, range_max) do { \ +#define xue(name, var, range_min, range_max, subs, ...) do { \ uint32_t value = range_min; \ CHECK(cbs_read_ue_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ &value, range_min, range_max)); \ var = value; \ } while (0) -#define xse(name, var, range_min, range_max) do { \ +#define xse(name, var, range_min, range_max, subs, ...) do { \ int32_t value = range_min; \ CHECK(cbs_read_se_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ &value, range_min, range_max)); \ var = value; \ } while (0) -#define u(width, name, range_min, range_max) \ - xu(width, name, current->name, range_min, range_max) -#define flag(name) u(1, name, 0, 1) -#define ue(name, range_min, range_max) \ - xue(name, current->name, range_min, range_max) -#define se(name, range_min, range_max) \ - xse(name, current->name, range_min, range_max) - #define infer(name, value) do { \ current->name = value; \ } while (0) @@ -291,9 +319,10 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc) #define byte_alignment(rw) (get_bits_count(rw) % 8) #define allocate(name, size) do { \ - name = av_mallocz(size); \ - if (!name) \ + name ## _ref = av_buffer_allocz(size); \ + if (!name ## _ref) \ return AVERROR(ENOMEM); \ + name = name ## _ref->data; \ } while (0) #define FUNC(name) FUNC_H264(READWRITE, name) @@ -310,10 +339,6 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc) #undef xu #undef xue #undef xse -#undef u -#undef flag -#undef ue -#undef se #undef infer #undef more_rbsp_data #undef byte_alignment @@ -324,30 +349,25 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc) #define READWRITE write #define RWContext PutBitContext -#define xu(width, name, var, range_min, range_max) do { \ +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ uint32_t value = var; \ CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ value, range_min, range_max)); \ } while (0) -#define xue(name, var, range_min, range_max) do { \ +#define xue(name, var, range_min, range_max, subs, ...) do { \ uint32_t value = var; \ CHECK(cbs_write_ue_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ value, range_min, range_max)); \ } while (0) -#define xse(name, var, range_min, range_max) do { \ +#define xse(name, var, range_min, range_max, subs, ...) do { \ int32_t value = var; \ CHECK(cbs_write_se_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ value, range_min, range_max)); \ } while (0) -#define u(width, name, range_min, range_max) \ - xu(width, name, current->name, range_min, range_max) -#define flag(name) u(1, name, 0, 1) -#define ue(name, range_min, range_max) \ - xue(name, current->name, range_min, range_max) -#define se(name, range_min, range_max) \ - xse(name, current->name, range_min, range_max) - #define infer(name, value) do { \ if (current->name != (value)) { \ av_log(ctx->log_ctx, AV_LOG_WARNING, "Warning: " \ @@ -393,82 +413,98 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc) #undef allocate -static void cbs_h264_free_sei(H264RawSEI *sei) +static void cbs_h264_free_pps(void *unit, uint8_t *content) { - int i; - for (i = 0; i < sei->payload_count; i++) { - H264RawSEIPayload *payload = &sei->payload[i]; - - switch (payload->payload_type) { - case H264_SEI_TYPE_BUFFERING_PERIOD: - case H264_SEI_TYPE_PIC_TIMING: - case H264_SEI_TYPE_RECOVERY_POINT: - case H264_SEI_TYPE_DISPLAY_ORIENTATION: - break; - case H264_SEI_TYPE_USER_DATA_REGISTERED: - av_freep(&payload->payload.user_data_registered.data); - break; - case H264_SEI_TYPE_USER_DATA_UNREGISTERED: - av_freep(&payload->payload.user_data_unregistered.data); - break; - default: - av_freep(&payload->payload.other.data); - break; - } + H264RawPPS *pps = (H264RawPPS*)content; + av_buffer_unref(&pps->slice_group_id_ref); + av_freep(&content); +} + +static void cbs_h264_free_sei_payload(H264RawSEIPayload *payload) +{ + switch (payload->payload_type) { + case H264_SEI_TYPE_BUFFERING_PERIOD: + case H264_SEI_TYPE_PIC_TIMING: + case H264_SEI_TYPE_PAN_SCAN_RECT: + case H264_SEI_TYPE_RECOVERY_POINT: + case H264_SEI_TYPE_DISPLAY_ORIENTATION: + case H264_SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME: + break; + case H264_SEI_TYPE_USER_DATA_REGISTERED: + av_buffer_unref(&payload->payload.user_data_registered.data_ref); + break; + case H264_SEI_TYPE_USER_DATA_UNREGISTERED: + av_buffer_unref(&payload->payload.user_data_unregistered.data_ref); + break; + default: + av_buffer_unref(&payload->payload.other.data_ref); + break; } } -static void cbs_h264_free_slice(H264RawSlice *slice) +static void cbs_h264_free_sei(void *unit, uint8_t *content) { - av_freep(&slice->data); + H264RawSEI *sei = (H264RawSEI*)content; + int i; + for (i = 0; i < sei->payload_count; i++) + cbs_h264_free_sei_payload(&sei->payload[i]); + av_freep(&content); } -static void cbs_h264_free_nal_unit(CodedBitstreamUnit *unit) +static void cbs_h264_free_slice(void *unit, uint8_t *content) { - switch (unit->type) { - case H264_NAL_SEI: - cbs_h264_free_sei(unit->content); - break; - case H264_NAL_IDR_SLICE: - case H264_NAL_SLICE: - cbs_h264_free_slice(unit->content); - break; - } - av_freep(&unit->content); + H264RawSlice *slice = (H264RawSlice*)content; + av_buffer_unref(&slice->data_ref); + av_freep(&content); } -static void cbs_h265_free_nal_unit(CodedBitstreamUnit *unit) +static void cbs_h265_free_vps(void *unit, uint8_t *content) { - switch (unit->type) { - case HEVC_NAL_VPS: - av_freep(&((H265RawVPS*)unit->content)->extension_data.data); - break; - case HEVC_NAL_SPS: - av_freep(&((H265RawSPS*)unit->content)->extension_data.data); - break; - case HEVC_NAL_PPS: - av_freep(&((H265RawPPS*)unit->content)->extension_data.data); + H265RawVPS *vps = (H265RawVPS*)content; + av_buffer_unref(&vps->extension_data.data_ref); + av_freep(&content); +} + +static void cbs_h265_free_sps(void *unit, uint8_t *content) +{ + H265RawSPS *sps = (H265RawSPS*)content; + av_buffer_unref(&sps->extension_data.data_ref); + av_freep(&content); +} + +static void cbs_h265_free_pps(void *unit, uint8_t *content) +{ + H265RawPPS *pps = (H265RawPPS*)content; + av_buffer_unref(&pps->extension_data.data_ref); + av_freep(&content); +} + +static void cbs_h265_free_slice(void *unit, uint8_t *content) +{ + H265RawSlice *slice = (H265RawSlice*)content; + av_buffer_unref(&slice->data_ref); + av_freep(&content); +} + +static void cbs_h265_free_sei_payload(H265RawSEIPayload *payload) +{ + switch (payload->payload_type) { + case HEVC_SEI_TYPE_MASTERING_DISPLAY_INFO: + case HEVC_SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO: break; - case HEVC_NAL_TRAIL_N: - case HEVC_NAL_TRAIL_R: - case HEVC_NAL_TSA_N: - case HEVC_NAL_TSA_R: - case HEVC_NAL_STSA_N: - case HEVC_NAL_STSA_R: - case HEVC_NAL_RADL_N: - case HEVC_NAL_RADL_R: - case HEVC_NAL_RASL_N: - case HEVC_NAL_RASL_R: - case HEVC_NAL_BLA_W_LP: - case HEVC_NAL_BLA_W_RADL: - case HEVC_NAL_BLA_N_LP: - case HEVC_NAL_IDR_W_RADL: - case HEVC_NAL_IDR_N_LP: - case HEVC_NAL_CRA_NUT: - av_freep(&((H265RawSlice*)unit->content)->data); + default: + av_buffer_unref(&payload->payload.other.data_ref); break; } - av_freep(&unit->content); +} + +static void cbs_h265_free_sei(void *unit, uint8_t *content) +{ + H265RawSEI *sei = (H265RawSEI*)content; + int i; + for (i = 0; i < sei->payload_count; i++) + cbs_h265_free_sei_payload(&sei->payload[i]); + av_freep(&content); } static int cbs_h2645_fragment_add_nals(CodedBitstreamContext *ctx, @@ -494,7 +530,7 @@ static int cbs_h2645_fragment_add_nals(CodedBitstreamContext *ctx, memset(data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); err = ff_cbs_insert_unit_data(ctx, frag, -1, nal->type, - data, size); + data, size, NULL); if (err < 0) { av_freep(&data); return err; @@ -665,20 +701,28 @@ static int cbs_h2645_split_fragment(CodedBitstreamContext *ctx, #define cbs_h2645_replace_ps(h26n, ps_name, ps_var, id_element) \ static int cbs_h26 ## h26n ## _replace_ ## ps_var(CodedBitstreamContext *ctx, \ - const H26 ## h26n ## Raw ## ps_name *ps_var) \ + CodedBitstreamUnit *unit) \ { \ CodedBitstreamH26 ## h26n ## Context *priv = ctx->priv_data; \ + H26 ## h26n ## Raw ## ps_name *ps_var = unit->content; \ unsigned int id = ps_var->id_element; \ if (id > FF_ARRAY_ELEMS(priv->ps_var)) { \ av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid " #ps_name \ " id : %d.\n", id); \ return AVERROR_INVALIDDATA; \ } \ - av_freep(&priv->ps_var[id]); \ - priv->ps_var[id] = av_malloc(sizeof(*ps_var)); \ - if (!priv->ps_var[id]) \ + if (priv->ps_var[id] == priv->active_ ## ps_var) \ + priv->active_ ## ps_var = NULL ; \ + av_buffer_unref(&priv->ps_var ## _ref[id]); \ + if (unit->content_ref) \ + priv->ps_var ## _ref[id] = av_buffer_ref(unit->content_ref); \ + else \ + priv->ps_var ## _ref[id] = av_buffer_alloc(sizeof(*ps_var)); \ + if (!priv->ps_var ## _ref[id]) \ return AVERROR(ENOMEM); \ - memcpy(priv->ps_var[id], ps_var, sizeof(*ps_var)); \ + priv->ps_var[id] = (H26 ## h26n ## Raw ## ps_name *)priv->ps_var ## _ref[id]->data; \ + if (!unit->content_ref) \ + memcpy(priv->ps_var[id], ps_var, sizeof(*ps_var)); \ return 0; \ } @@ -703,35 +747,32 @@ static int cbs_h264_read_nal_unit(CodedBitstreamContext *ctx, { H264RawSPS *sps; - sps = av_mallocz(sizeof(*sps)); - if (!sps) - return AVERROR(ENOMEM); + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*sps), NULL); + if (err < 0) + return err; + sps = unit->content; + err = cbs_h264_read_sps(ctx, &gbc, sps); - if (err >= 0) - err = cbs_h264_replace_sps(ctx, sps); - if (err < 0) { - av_free(sps); + if (err < 0) return err; - } - unit->content = sps; + err = cbs_h264_replace_sps(ctx, unit); + if (err < 0) + return err; } break; case H264_NAL_SPS_EXT: { - H264RawSPSExtension *sps_ext; - - sps_ext = av_mallocz(sizeof(*sps_ext)); - if (!sps_ext) - return AVERROR(ENOMEM); - err = cbs_h264_read_sps_extension(ctx, &gbc, sps_ext); - if (err < 0) { - av_free(sps_ext); + err = ff_cbs_alloc_unit_content(ctx, unit, + sizeof(H264RawSPSExtension), + NULL); + if (err < 0) return err; - } - unit->content = sps_ext; + err = cbs_h264_read_sps_extension(ctx, &gbc, unit->content); + if (err < 0) + return err; } break; @@ -739,18 +780,19 @@ static int cbs_h264_read_nal_unit(CodedBitstreamContext *ctx, { H264RawPPS *pps; - pps = av_mallocz(sizeof(*pps)); - if (!pps) - return AVERROR(ENOMEM); + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*pps), + &cbs_h264_free_pps); + if (err < 0) + return err; + pps = unit->content; + err = cbs_h264_read_pps(ctx, &gbc, pps); - if (err >= 0) - err = cbs_h264_replace_pps(ctx, pps); - if (err < 0) { - av_free(pps); + if (err < 0) return err; - } - unit->content = pps; + err = cbs_h264_replace_pps(ctx, unit); + if (err < 0) + return err; } break; @@ -761,14 +803,15 @@ static int cbs_h264_read_nal_unit(CodedBitstreamContext *ctx, H264RawSlice *slice; int pos, len; - slice = av_mallocz(sizeof(*slice)); - if (!slice) - return AVERROR(ENOMEM); + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*slice), + &cbs_h264_free_slice); + if (err < 0) + return err; + slice = unit->content; + err = cbs_h264_read_slice_header(ctx, &gbc, &slice->header); - if (err < 0) { - av_free(slice); + if (err < 0) return err; - } pos = get_bits_count(&gbc); len = unit->data_size; @@ -781,54 +824,50 @@ static int cbs_h264_read_nal_unit(CodedBitstreamContext *ctx, } slice->data_size = len - pos / 8; - slice->data = av_malloc(slice->data_size + - AV_INPUT_BUFFER_PADDING_SIZE); - if (!slice->data) { - av_free(slice); + slice->data_ref = av_buffer_ref(unit->data_ref); + if (!slice->data_ref) return AVERROR(ENOMEM); - } - memcpy(slice->data, - unit->data + pos / 8, slice->data_size); - memset(slice->data + slice->data_size, 0, - AV_INPUT_BUFFER_PADDING_SIZE); + slice->data = unit->data + pos / 8; slice->data_bit_start = pos % 8; - - unit->content = slice; } break; case H264_NAL_AUD: { - H264RawAUD *aud; - - aud = av_mallocz(sizeof(*aud)); - if (!aud) - return AVERROR(ENOMEM); - err = cbs_h264_read_aud(ctx, &gbc, aud); - if (err < 0) { - av_free(aud); + err = ff_cbs_alloc_unit_content(ctx, unit, + sizeof(H264RawAUD), NULL); + if (err < 0) return err; - } - unit->content = aud; + err = cbs_h264_read_aud(ctx, &gbc, unit->content); + if (err < 0) + return err; } break; case H264_NAL_SEI: { - H264RawSEI *sei; + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(H264RawSEI), + &cbs_h264_free_sei); + if (err < 0) + return err; - sei = av_mallocz(sizeof(*sei)); - if (!sei) - return AVERROR(ENOMEM); - err = cbs_h264_read_sei(ctx, &gbc, sei); - if (err < 0) { - cbs_h264_free_sei(sei); - av_free(sei); + err = cbs_h264_read_sei(ctx, &gbc, unit->content); + if (err < 0) return err; - } + } + break; - unit->content = sei; + case H264_NAL_FILLER_DATA: + { + err = ff_cbs_alloc_unit_content(ctx, unit, + sizeof(H264RawFiller), NULL); + if (err < 0) + return err; + + err = cbs_h264_read_filler(ctx, &gbc, unit->content); + if (err < 0) + return err; } break; @@ -854,36 +893,38 @@ static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, { H265RawVPS *vps; - vps = av_mallocz(sizeof(*vps)); - if (!vps) - return AVERROR(ENOMEM); + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*vps), + &cbs_h265_free_vps); + if (err < 0) + return err; + vps = unit->content; + err = cbs_h265_read_vps(ctx, &gbc, vps); - if (err >= 0) - err = cbs_h265_replace_vps(ctx, vps); - if (err < 0) { - av_free(vps); + if (err < 0) return err; - } - unit->content = vps; + err = cbs_h265_replace_vps(ctx, unit); + if (err < 0) + return err; } break; case HEVC_NAL_SPS: { H265RawSPS *sps; - sps = av_mallocz(sizeof(*sps)); - if (!sps) - return AVERROR(ENOMEM); + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*sps), + &cbs_h265_free_sps); + if (err < 0) + return err; + sps = unit->content; + err = cbs_h265_read_sps(ctx, &gbc, sps); - if (err >= 0) - err = cbs_h265_replace_sps(ctx, sps); - if (err < 0) { - av_free(sps); + if (err < 0) return err; - } - unit->content = sps; + err = cbs_h265_replace_sps(ctx, unit); + if (err < 0) + return err; } break; @@ -891,18 +932,19 @@ static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, { H265RawPPS *pps; - pps = av_mallocz(sizeof(*pps)); - if (!pps) - return AVERROR(ENOMEM); + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*pps), + &cbs_h265_free_pps); + if (err < 0) + return err; + pps = unit->content; + err = cbs_h265_read_pps(ctx, &gbc, pps); - if (err >= 0) - err = cbs_h265_replace_pps(ctx, pps); - if (err < 0) { - av_free(pps); + if (err < 0) return err; - } - unit->content = pps; + err = cbs_h265_replace_pps(ctx, unit); + if (err < 0) + return err; } break; @@ -926,14 +968,15 @@ static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, H265RawSlice *slice; int pos, len; - slice = av_mallocz(sizeof(*slice)); - if (!slice) - return AVERROR(ENOMEM); + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*slice), + &cbs_h265_free_slice); + if (err < 0) + return err; + slice = unit->content; + err = cbs_h265_read_slice_segment_header(ctx, &gbc, &slice->header); - if (err < 0) { - av_free(slice); + if (err < 0) return err; - } pos = get_bits_count(&gbc); len = unit->data_size; @@ -946,36 +989,39 @@ static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, } slice->data_size = len - pos / 8; - slice->data = av_malloc(slice->data_size + - AV_INPUT_BUFFER_PADDING_SIZE); - if (!slice->data) { - av_free(slice); + slice->data_ref = av_buffer_ref(unit->data_ref); + if (!slice->data_ref) return AVERROR(ENOMEM); - } - memcpy(slice->data, - unit->data + pos / 8, slice->data_size); - memset(slice->data + slice->data_size, 0, - AV_INPUT_BUFFER_PADDING_SIZE); + slice->data = unit->data + pos / 8; slice->data_bit_start = pos % 8; - - unit->content = slice; } break; case HEVC_NAL_AUD: { - H265RawAUD *aud; + err = ff_cbs_alloc_unit_content(ctx, unit, + sizeof(H265RawAUD), NULL); + if (err < 0) + return err; - aud = av_mallocz(sizeof(*aud)); - if (!aud) - return AVERROR(ENOMEM); - err = cbs_h265_read_aud(ctx, &gbc, aud); - if (err < 0) { - av_free(aud); + err = cbs_h265_read_aud(ctx, &gbc, unit->content); + if (err < 0) return err; - } + } + break; - unit->content = aud; + case HEVC_NAL_SEI_PREFIX: + { + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(H265RawSEI), + &cbs_h265_free_sei); + + if (err < 0) + return err; + + err = cbs_h265_read_sei(ctx, &gbc, unit->content); + + if (err < 0) + return err; } break; @@ -1001,7 +1047,7 @@ static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx, if (err < 0) return err; - err = cbs_h264_replace_sps(ctx, sps); + err = cbs_h264_replace_sps(ctx, unit); if (err < 0) return err; } @@ -1025,7 +1071,7 @@ static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx, if (err < 0) return err; - err = cbs_h264_replace_pps(ctx, pps); + err = cbs_h264_replace_pps(ctx, unit); if (err < 0) return err; } @@ -1090,6 +1136,14 @@ static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx, } break; + case H264_NAL_FILLER_DATA: + { + err = cbs_h264_write_filler(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + default: av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for " "NAL unit type %"PRIu32".\n", unit->type); @@ -1114,7 +1168,7 @@ static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx, if (err < 0) return err; - err = cbs_h265_replace_vps(ctx, vps); + err = cbs_h265_replace_vps(ctx, unit); if (err < 0) return err; } @@ -1128,7 +1182,7 @@ static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx, if (err < 0) return err; - err = cbs_h265_replace_sps(ctx, sps); + err = cbs_h265_replace_sps(ctx, unit); if (err < 0) return err; } @@ -1142,7 +1196,7 @@ static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx, if (err < 0) return err; - err = cbs_h265_replace_pps(ctx, pps); + err = cbs_h265_replace_pps(ctx, unit); if (err < 0) return err; } @@ -1211,6 +1265,15 @@ static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx, } break; + case HEVC_NAL_SEI_PREFIX: + { + err = cbs_h265_write_sei(ctx, pbc, unit->content); + + if (err < 0) + return err; + } + break; + default: av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for " "NAL unit type %"PRIu32".\n", unit->type); @@ -1270,7 +1333,7 @@ static int cbs_h2645_write_nal_unit(CodedBitstreamContext *ctx, unit->data_size = (put_bits_count(&pbc) + 7) / 8; flush_put_bits(&pbc); - err = av_reallocp(&unit->data, unit->data_size); + err = ff_cbs_alloc_unit_data(ctx, unit, unit->data_size); if (err < 0) return err; @@ -1297,7 +1360,7 @@ static int cbs_h2645_assemble_fragment(CodedBitstreamContext *ctx, max_size += 3 + frag->units[i].data_size * 3 / 2; } - data = av_malloc(max_size); + data = av_malloc(max_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!data) return AVERROR(ENOMEM); @@ -1348,9 +1411,17 @@ static int cbs_h2645_assemble_fragment(CodedBitstreamContext *ctx, } av_assert0(dp <= max_size); - err = av_reallocp(&data, dp); + err = av_reallocp(&data, dp + AV_INPUT_BUFFER_PADDING_SIZE); if (err) return err; + memset(data + dp, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + frag->data_ref = av_buffer_create(data, dp + AV_INPUT_BUFFER_PADDING_SIZE, + NULL, NULL, 0); + if (!frag->data_ref) { + av_freep(&data); + return AVERROR(ENOMEM); + } frag->data = data; frag->data_size = dp; @@ -1368,9 +1439,9 @@ static void cbs_h264_close(CodedBitstreamContext *ctx) av_freep(&h264->common.write_buffer); for (i = 0; i < FF_ARRAY_ELEMS(h264->sps); i++) - av_freep(&h264->sps[i]); + av_buffer_unref(&h264->sps_ref[i]); for (i = 0; i < FF_ARRAY_ELEMS(h264->pps); i++) - av_freep(&h264->pps[i]); + av_buffer_unref(&h264->pps_ref[i]); } static void cbs_h265_close(CodedBitstreamContext *ctx) @@ -1383,11 +1454,11 @@ static void cbs_h265_close(CodedBitstreamContext *ctx) av_freep(&h265->common.write_buffer); for (i = 0; i < FF_ARRAY_ELEMS(h265->vps); i++) - av_freep(&h265->vps[i]); + av_buffer_unref(&h265->vps_ref[i]); for (i = 0; i < FF_ARRAY_ELEMS(h265->sps); i++) - av_freep(&h265->sps[i]); + av_buffer_unref(&h265->sps_ref[i]); for (i = 0; i < FF_ARRAY_ELEMS(h265->pps); i++) - av_freep(&h265->pps[i]); + av_buffer_unref(&h265->pps_ref[i]); } const CodedBitstreamType ff_cbs_type_h264 = { @@ -1400,7 +1471,6 @@ const CodedBitstreamType ff_cbs_type_h264 = { .write_unit = &cbs_h2645_write_nal_unit, .assemble_fragment = &cbs_h2645_assemble_fragment, - .free_unit = &cbs_h264_free_nal_unit, .close = &cbs_h264_close, }; @@ -1414,6 +1484,100 @@ const CodedBitstreamType ff_cbs_type_h265 = { .write_unit = &cbs_h2645_write_nal_unit, .assemble_fragment = &cbs_h2645_assemble_fragment, - .free_unit = &cbs_h265_free_nal_unit, .close = &cbs_h265_close, }; + +int ff_cbs_h264_add_sei_message(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + const H264RawSEIPayload *payload) +{ + H264RawSEI *sei; + CodedBitstreamUnit *nal = NULL; + int err, i; + + // Find an existing SEI NAL unit to add to. + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == H264_NAL_SEI) { + nal = &au->units[i]; + break; + } + } + if (nal) { + sei = nal->content; + + } else { + // 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) + return AVERROR(ENOMEM); + + sei->nal_unit_header.nal_unit_type = H264_NAL_SEI; + sei->nal_unit_header.nal_ref_idc = 0; + + sei_ref = av_buffer_create((uint8_t*)sei, sizeof(*sei), + &cbs_h264_free_sei, ctx, 0); + if (!sei_ref) { + av_freep(&sei); + return AVERROR(ENOMEM); + } + + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == H264_NAL_SLICE || + au->units[i].type == H264_NAL_IDR_SLICE) + break; + } + + err = ff_cbs_insert_unit_content(ctx, au, i, H264_NAL_SEI, + sei, sei_ref); + av_buffer_unref(&sei_ref); + if (err < 0) + return err; + } + + if (sei->payload_count >= H264_MAX_SEI_PAYLOADS) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many payloads in " + "SEI NAL unit.\n"); + return AVERROR(EINVAL); + } + + memcpy(&sei->payload[sei->payload_count], payload, sizeof(*payload)); + ++sei->payload_count; + + return 0; +} + +int ff_cbs_h264_delete_sei_message(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + CodedBitstreamUnit *nal, + int position) +{ + H264RawSEI *sei = nal->content; + + av_assert0(nal->type == H264_NAL_SEI); + 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; + } + av_assert0(i < au->nb_units && "NAL unit not in access unit."); + + return ff_cbs_delete_unit(ctx, au, i); + } else { + cbs_h264_free_sei_payload(&sei->payload[position]); + + --sei->payload_count; + memmove(sei->payload + position, + sei->payload + position + 1, + (sei->payload_count - position) * sizeof(*sei->payload)); + + return 0; + } +}