Skip to content

Commit

Permalink
Fixed Simplify prepend instruction.
Browse files Browse the repository at this point in the history
  • Loading branch information
Yunus Kurt committed Mar 20, 2024
1 parent 7f32227 commit 719a119
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 105 deletions.
81 changes: 69 additions & 12 deletions lib/src/includes/signed_video_sign.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,62 @@ signed_video_add_nalu_for_signing(signed_video_t *self,
/**
* @brief Gets generated NALUs to prepend the latest added NALU
*
* This function is replaced by signed_video_get_sei.
* This function should always be called after a successful
* signed_video_add_nalu_for_signing_with_timestamp(...). Otherwise, the functionality of Signed
* Video is jeopardized, since vital SEI-NALUs may not be added to the video stream. The
* signed_video_add_nalu_for_signing_with_timestamp(...) returns SV_NOT_SUPPORTED if there are
* available NALUs to prepend. The user should then pull these before continuing; See return values
* in signed_video_add_nalu_for_signing_with_timestamp(...).
*
* These SEI-NALUs are generated by the Signed Video library and are complete NALUs + 4 start code
* bytes. Hence, the user can simply pull and prepend existing H26x NALUs. Pull NALUs to prepend
* from signed_video_t one by one until no further action is required. When this happens, a
* SIGNED_VIDEO_PREPEND_NOTHING instruction is pulled. The signed_video_get_nalu_to_prepend(...)
* API provides the user with the NALU data as well as instructions on where to prepend that data.
*
* NOTE that as soon as the user pulls a new NALU to prepend, the ownership of the |nalu_data|
* memory (see members of signed_video_nalu_to_prepend_t) is transferred. Free the |nalu_data|
* memory with signed_video_nalu_data_free(...).
*
* Here is an example code of usage:
*
* signed_video_t *sv = signed_video_create(SV_CODEC_H264);
* if (!sv) {
* // Handle error
* }
* if (signed_video_set_private_key(sv, SIGN_ALGO_ECDSA, private_key, private_key_size)
* != SV_OK) {
* // Handle error
* }
* SignedVideoReturnCode status;
* status = signed_video_add_nalu_for_signing_with_timestamp(sv, nalu, nalu_size, NULL);
* if (status != SV_OK) {
* // Handle error
* } else {
* signed_video_nalu_to_prepend_t nalu_to_prepend;
* status = signed_video_get_nalu_to_prepend(sv, &nalu_to_prepend);
* while (status == SV_OK &&
* nalu_to_prepend.prepend_instruction != SIGNED_VIDEO_PREPEND_NOTHING) {
* switch (nalu_to_prepend.prepend_instruction) {
* case (SIGNED_VIDEO_PREPEND_ACCESS_UNIT):
* // Add an extra access unit (AU) before current AU, or prepend the
* // NALUs if an extra AU has already been created.
* break;
* case (SIGNED_VIDEO_PREPEND_NALU):
* // Prepend the NALUs in the current AU.
* break;
* default:
* break;
* }
* // Maybe free the |nalu_data| before pulling a new |nalu_to_prepend|.
* // signed_video_nalu_data_free(nalu_to_prepend.nalu_data);
* status = signed_video_get_nalu_to_prepend(sv, &nalu_to_prepend);
* }
* // Handle return code
* if (status != SV_OK) {
* // True error. Handle it properly.
* }
* }
*
* @param self Pointer to the signed_video_t object in use.
* @param nalu_to_prepend A pointer to a signed_video_nalu_to_prepend_t object holding NALU data
Expand All @@ -172,8 +227,7 @@ signed_video_get_nalu_to_prepend(signed_video_t *self,
signed_video_nalu_to_prepend_t *nalu_to_prepend);

/**
* @brief Copies the Sei Payload from the Sei Buffer to allocated
* memory thats provided by user.
* @brief Gets generated SEIs to add to the stream
*
* This function should always be called after a successful
* signed_video_add_nalu_for_signing_with_timestamp(...). Otherwise, the functionality of Signed
Expand All @@ -184,8 +238,8 @@ signed_video_get_nalu_to_prepend(signed_video_t *self,
*
* These SEI-NALUs are generated by the Signed Video library and are complete NALUs + 4 start code
* bytes. Hence, the user can simply pull and prepend existing H26x NALUs. Pull NALUs to prepend
* from signed_video_t one by one until no further action is required. When this happens, data_size
* is 0.
* from signed_video_t one by one until no more generated SEIs exists, that is, when |sei_size|
* is zero.
* API provides the user with the NALU data as well as instructions on where to prepend that data.
*
* NOTE that as soon as the user pulls a new NALU to prepend, the ownership of the |nalu_data|
Expand All @@ -207,10 +261,12 @@ signed_video_get_nalu_to_prepend(signed_video_t *self,
* if (status != SV_OK) {
* // Handle error
* } else {
* size_t data_size = 0;
* status = signed_video_get_sei(sv, NULL, &data_size);
* uint8_t *nalu_data = malloc(data_size);
* status = signed_video_get_sei(sv, nalu_data, &data_size);
* size_t sei_size = 0;
* status = signed_video_get_sei(sv, NULL, &sei_size);
* // The first call of the function is for getiing the sei_size.
* // The Second call is to get the sei.
* uint8_t *sei = malloc(sei_size);
* status = signed_video_get_sei(sv, sei, &sei_size);
* while (status == SV_OK &&
* data_size != 0) {
* break;
Expand All @@ -223,15 +279,16 @@ signed_video_get_nalu_to_prepend(signed_video_t *self,
* }
*
* @param self Pointer to the signed_video_t object in use.
* @param nalu_data Pointer to the SEI payload
* @param nalu_data_size Size of the NAlU
* @param sei Pointer to the memory to which a complete SEI will be copied.
* If a NULL pointer is used, only the |sei_size| is updated.
* @param sei_size Pointer to where the size of the SEI is written.
*
* @returns SV_OK - NALU was pulled successfully,
* SV_NOT_SUPPORTED - no available data, the action is not supported,
* otherwise - an error code.
*/
SignedVideoReturnCode
signed_video_get_sei(signed_video_t *self, uint8_t *nalu_data, size_t *nalu_data_size);
signed_video_get_sei(signed_video_t *self, uint8_t *sei, size_t *sei_size);

/**
* @brief Frees the |nalu_data| of signed_video_nalu_to_prepend_t
Expand Down
74 changes: 48 additions & 26 deletions lib/src/signed_video_h26x_sign.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,11 @@ complete_sei_nalu_and_add_to_prepend(signed_video_t *self)
assert(sei_data_buffer_end <= MAX_NALUS_TO_PREPEND);
size_t data_size = 0;
svi_rc status = SVI_UNKNOWN;
sei_data_t *nalu_to_prepend = &(self->sei_data_buffer[self->num_of_completed_seis]);
sei_data_t *sei_data = &(self->sei_data_buffer[self->num_of_completed_seis]);
// Transfer oldest pointer in |payload_buffer| to local |payload|
uint8_t *payload = nalu_to_prepend->payload;
uint8_t *payload_signature_ptr = nalu_to_prepend->payload_signature_ptr;
self->last_two_bytes = nalu_to_prepend->last_two_bytes;
uint8_t *payload = sei_data->payload;
uint8_t *payload_signature_ptr = sei_data->payload_signature_ptr;
self->last_two_bytes = sei_data->last_two_bytes;

// If the signature could not be generated |signature_size| equals zero. Free the started SEI and
// move on. This is a valid operation. What will happen is that the video will have an unsigned
Expand All @@ -135,11 +135,8 @@ complete_sei_nalu_and_add_to_prepend(signed_video_t *self)
// Add the signature to the SEI payload.
data_size = get_sign_and_complete_sei_nalu(self, &payload, payload_signature_ptr);
SVI_THROW_IF(!data_size, SVI_UNKNOWN);
// Add created SEI to the prepend list.
// TODO: Include setting |nalu_data| in add_nalu_to_prepend().
// Transfer |payload| to |nalu_to_prepend|.
nalu_to_prepend->sei_data = payload;
nalu_to_prepend->sei_size = data_size;
sei_data->completed_sei = payload;
sei_data->completed_sei_size = data_size;
self->num_of_completed_seis++;

// Unset flag when SEI is completed and prepended.
Expand All @@ -157,7 +154,7 @@ complete_sei_nalu_and_add_to_prepend(signed_video_t *self)

/* Removes the first element from the SEI buffer of a `signed_video_t` structure,
* shifting remaining elements left and clearing the last slot. */
void
static void
shift_sei_buffer_index(signed_video_t *self)
{
const int sei_data_buffer_end = self->sei_data_buffer_idx;
Expand Down Expand Up @@ -432,10 +429,8 @@ prepare_for_nalus_to_prepend(signed_video_t *self)
// empty list item, the pull action has no impact. We can therefore silently remove it and
// proceed. But if there are vital SEI-nalus waiting to be pulled we return an error message
// (SV_NOT_SUPPORTED).
SVI_THROW_IF_WITH_MSG(self->num_of_completed_seis > 0, SVI_NOT_SUPPORTED,
"There are remaining NALUs in list to prepend");
if (self->num_of_completed_seis > 0) self->num_of_completed_seis = 0;

SVI_THROW_IF_WITH_MSG(
self->num_of_completed_seis > 0, SVI_NOT_SUPPORTED, "There are remainin SEI's.");
// Add an empty nalu_to_prepend item to the queue. This first item in the nalus_to_prepend_list
// is always empty, hence we can simply increment the queue counter. The reason to have an empty
// NALU is to be able to signal the end of the list with a proper instruction at the end.
Expand Down Expand Up @@ -578,32 +573,59 @@ signed_video_add_nalu_part_for_signing_with_timestamp(signed_video_t *self,
}

SignedVideoReturnCode
signed_video_get_sei(signed_video_t *self, uint8_t *nalu_data, size_t *nalu_data_size)
signed_video_get_sei(signed_video_t *self, uint8_t *sei, size_t *sei_size)
{

if (!self || !nalu_data_size) return SV_INVALID_PARAMETER;
*nalu_data_size = 0;
if (!self || !sei_size) return SV_INVALID_PARAMETER;
*sei_size = 0;
if (self->num_of_completed_seis < 1) {
DEBUG_LOG("No items in |nalus_to_prepend_list|");
DEBUG_LOG("There are no completed seis.");
return SV_OK;
}
if (!nalu_data) {
// Assign the NALU size to the provided pointers.
*nalu_data_size = self->sei_data_buffer[0].sei_size;
if (!sei) {
// Assign the SEI size to the provided pointers.
*sei_size = self->sei_data_buffer[0].completed_sei_size;
return SV_OK;
}
// Assign the NALU size and NALU data to the provided pointers.
*nalu_data_size = self->sei_data_buffer[0].sei_size;
memcpy(nalu_data, self->sei_data_buffer[0].payload, *nalu_data_size);
// Assign the SEI size and SEI data to the provided pointers.
*sei_size = self->sei_data_buffer[0].completed_sei_size;
memcpy(sei, self->sei_data_buffer[0].payload, *sei_size);

// Reset the fetched NALU information from the sei buffer.
// Reset the fetched SEI information from the sei buffer.
signed_video_nalu_data_free(self->sei_data_buffer[0].payload);

--(self->num_of_completed_seis);
shift_sei_buffer_index(self);
return SV_OK;
}

static SignedVideoReturnCode
signed_video_get_lastest_sei(signed_video_t *self, uint8_t *sei, size_t *sei_size)
{

if (!self || !sei_size) return SV_INVALID_PARAMETER;
*sei_size = 0;
if (self->num_of_completed_seis < 1) {
DEBUG_LOG("There are no completed seis.");
return SV_OK;
}
if (!sei) {
// Assign the SEI size to the provided pointers.
*sei_size = self->sei_data_buffer[self->num_of_completed_seis].completed_sei_size;
return SV_OK;
}
// Assign the SEI size and SEI data to the provided pointers.
*sei_size = self->sei_data_buffer[self->num_of_completed_seis].completed_sei_size;
memcpy(sei, self->sei_data_buffer[self->num_of_completed_seis].payload, *sei_size);

// Reset the fetched SEI information from the sei buffer.
signed_video_nalu_data_free(self->sei_data_buffer[self->num_of_completed_seis].payload);

--(self->num_of_completed_seis);
shift_sei_buffer_index(self);
return SV_OK;
}

SignedVideoReturnCode
signed_video_get_nalu_to_prepend(signed_video_t *self,
signed_video_nalu_to_prepend_t *nalu_to_prepend)
Expand All @@ -620,7 +642,7 @@ signed_video_get_nalu_to_prepend(signed_video_t *self,
} else {
nalu_to_prepend->prepend_instruction = SIGNED_VIDEO_PREPEND_NOTHING;
}
return signed_video_get_sei(
return signed_video_get_lastest_sei(
self, (nalu_to_prepend->nalu_data), &(nalu_to_prepend->nalu_data_size));
}

Expand Down
8 changes: 3 additions & 5 deletions lib/src/signed_video_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ struct _sei_data_t {
uint8_t *payload; // Pointer to the allocated SEI data
uint8_t *payload_signature_ptr;
uint16_t last_two_bytes;
uint8_t *sei_data; // nalu_data = payload
size_t sei_size; // nalu_data_size = payload_signature_ptr - payload
uint8_t *completed_sei; // nalu_data = payload
size_t completed_sei_size; // nalu_data_size = payload_signature_ptr - payload
};

struct _signed_video_t {
Expand All @@ -122,11 +122,9 @@ struct _signed_video_t {
bool sei_epb; // Flag that tells whether to generate SEI frames w/wo emulation prevention bytes
size_t max_sei_payload_size; // Default 0 = unlimited

// Frames to prepend list
int num_of_completed_seis;

sei_data_t sei_data_buffer[MAX_NALUS_TO_PREPEND];
int sei_data_buffer_idx;
int num_of_completed_seis;

// TODO: Collect everything needed by the authentication part only in one struct/object, which
// then is not needed to be created on the signing side, saving some memory.
Expand Down
7 changes: 4 additions & 3 deletions tests/check/check_h26xsigned_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -1715,7 +1715,6 @@ START_TEST(vendor_axis_communications_operation)
SignedVideoCodec codec = settings[_i].codec;
sign_algo_t algo = settings[_i].algo;
SignedVideoAuthenticityLevel auth_level = settings[_i].auth_level;

nalu_list_item_t *i_nalu = nalu_list_item_create_and_set_id('I', 0, codec);
nalu_list_item_t *sei = NULL;
char *private_key = NULL;
Expand Down Expand Up @@ -1751,13 +1750,13 @@ START_TEST(vendor_axis_communications_operation)
sv_rc = signed_video_add_nalu_for_signing(sv, i_nalu->data, i_nalu->data_size);
ck_assert_int_eq(sv_rc, SV_OK);
sv_rc = signed_video_get_sei(sv, NULL, &sei_size);
ck_assert(sei_size > 0);
ck_assert_int_eq(sv_rc, SV_OK);
uint8_t *nalu_data = malloc(sei_size);
sv_rc = signed_video_get_sei(sv, nalu_data, &sei_size);
ck_assert_int_eq(sv_rc, SV_OK);
sei = nalu_list_create_item(nalu_data, sei_size, codec);
ck_assert(tag_is_present(sei, codec, VENDOR_AXIS_COMMUNICATIONS_TAG));
// Ownership of |nalu_to_prepend.nalu_data| has been transferred. Do not free memory.
sv_rc = signed_video_get_sei(sv, NULL, &sei_size);
ck_assert_int_eq(sv_rc, SV_OK);
ck_assert(sei_size == 0);
Expand Down Expand Up @@ -1814,7 +1813,6 @@ generate_and_set_private_key_on_camera_side(struct sv_setting setting,
char *private_key = NULL;
size_t private_key_size = 0;
nalu_list_item_t *i_nalu = nalu_list_item_create_and_set_id('I', 0, setting.codec);
size_t sei_size;
signed_video_t *sv = signed_video_create(setting.codec);
ck_assert(sv);
// Read and set content of private_key.
Expand All @@ -1831,7 +1829,10 @@ generate_and_set_private_key_on_camera_side(struct sv_setting setting,
// Add an I-NALU to trigger a SEI.
sv_rc = signed_video_add_nalu_for_signing(sv, i_nalu->data, i_nalu->data_size);
ck_assert_int_eq(sv_rc, SV_OK);

size_t sei_size = 0;
sv_rc = signed_video_get_sei(sv, NULL, &sei_size);
ck_assert(sei_size > 0);
ck_assert_int_eq(sv_rc, SV_OK);
uint8_t *nalu_data = malloc(sei_size);
sv_rc = signed_video_get_sei(sv, nalu_data, &sei_size);
Expand Down
Loading

0 comments on commit 719a119

Please sign in to comment.