From 17dc844881ad526b91c9e556e0870984f752a562 Mon Sep 17 00:00:00 2001 From: Adriaan Niess Date: Thu, 27 Jun 2024 17:37:24 +0200 Subject: [PATCH 1/3] Refactore CVF format Signed-off-by: Adriaan Niess --- examples/cvf/cvf-listener.c | 565 ++++++++++++++++--------------- examples/cvf/cvf-talker.c | 412 +++++++++++----------- include/avtp/cvf/Cvf.h | 103 ++++++ include/avtp/cvf/H264.h | 54 +++ include/avtp/cvf/Jpeg2000.h | 61 ++++ include/avtp/cvf/Mjpeg.h | 59 ++++ include/avtp_cvf.h | 107 ------ meson.build | 13 +- src/avtp/cvf/Cvf.c | 111 ++++++ src/avtp/cvf/H264.c | 57 ++++ src/avtp/cvf/Jpeg2000.c | 64 ++++ src/avtp/cvf/Mjpeg.c | 62 ++++ src/avtp_cvf.c | 254 -------------- unit/test-cvf.c | 657 +++++++++++++++++------------------- 14 files changed, 1377 insertions(+), 1202 deletions(-) create mode 100644 include/avtp/cvf/Cvf.h create mode 100644 include/avtp/cvf/H264.h create mode 100644 include/avtp/cvf/Jpeg2000.h create mode 100644 include/avtp/cvf/Mjpeg.h delete mode 100644 include/avtp_cvf.h create mode 100644 src/avtp/cvf/Cvf.c create mode 100644 src/avtp/cvf/H264.c create mode 100644 src/avtp/cvf/Jpeg2000.c create mode 100644 src/avtp/cvf/Mjpeg.c delete mode 100644 src/avtp_cvf.c diff --git a/examples/cvf/cvf-listener.c b/examples/cvf/cvf-listener.c index 2d325a3..37ad835 100644 --- a/examples/cvf/cvf-listener.c +++ b/examples/cvf/cvf-listener.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, COVESA * Copyright (c) 2019, Intel Corporation * * Redistribution and use in source and binary forms, with or without @@ -9,9 +10,9 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * * Neither the name of COVESA, Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -23,6 +24,8 @@ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ /* CVF Listener example. @@ -67,24 +70,26 @@ #include #include #include +#include #include "avtp.h" -#include "avtp_cvf.h" -#include "common.h" +#include "avtp/cvf/Cvf.h" +#include "avtp/cvf/H264.h" #include "avtp/CommonHeader.h" +#include "examples/common.h" -#define STREAM_ID 0xAABBCCDDEEFF0001 -#define DATA_LEN 1400 -#define AVTP_H264_HEADER_LEN (sizeof(uint32_t)) -#define AVTP_FULL_HEADER_LEN (sizeof(struct avtp_stream_pdu) + AVTP_H264_HEADER_LEN) -#define MAX_PDU_SIZE (AVTP_FULL_HEADER_LEN + DATA_LEN) +#define STREAM_ID 0xAABBCCDDEEFF0001 +#define DATA_LEN 1400 +#define AVTP_H264_HEADER_LEN (sizeof(Avtp_H264_t)) +#define AVTP_FULL_HEADER_LEN (sizeof(Avtp_Cvf_t) + sizeof(Avtp_H264_t)) +#define MAX_PDU_SIZE (AVTP_FULL_HEADER_LEN + DATA_LEN) struct nal_entry { - STAILQ_ENTRY(nal_entry) entries; + STAILQ_ENTRY(nal_entry) entries; - uint16_t len; - struct timespec tspec; - uint8_t nal[DATA_LEN]; + uint16_t len; + struct timespec tspec; + uint8_t nal[DATA_LEN]; }; static STAILQ_HEAD(nal_queue, nal_entry) nals; @@ -93,313 +98,307 @@ static uint8_t macaddr[ETH_ALEN]; static uint8_t expected_seq; static struct argp_option options[] = { - {"dst-addr", 'd', "MACADDR", 0, "Stream Destination MAC address" }, - {"ifname", 'i', "IFNAME", 0, "Network Interface" }, - { 0 } + {"dst-addr", 'd', "MACADDR", 0, "Stream Destination MAC address" }, + {"ifname", 'i', "IFNAME", 0, "Network Interface" }, + { 0 } }; static error_t parser(int key, char *arg, struct argp_state *state) { - int res; - - switch (key) { - case 'd': - res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", - &macaddr[0], &macaddr[1], &macaddr[2], - &macaddr[3], &macaddr[4], &macaddr[5]); - if (res != 6) { - fprintf(stderr, "Invalid address\n"); - exit(EXIT_FAILURE); - } - - break; - case 'i': - strncpy(ifname, arg, sizeof(ifname) - 1); - break; - } - - return 0; + int res; + + switch (key) { + case 'd': + res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &macaddr[0], &macaddr[1], &macaddr[2], + &macaddr[3], &macaddr[4], &macaddr[5]); + if (res != 6) { + fprintf(stderr, "Invalid address\n"); + exit(EXIT_FAILURE); + } + + break; + case 'i': + strncpy(ifname, arg, sizeof(ifname) - 1); + break; + } + + return 0; } static struct argp argp = { options, parser }; static int schedule_nal(int fd, struct timespec *tspec, uint8_t *nal, - ssize_t len) + ssize_t len) { - struct nal_entry *entry; - - entry = malloc(sizeof(*entry)); - if (!entry) { - fprintf(stderr, "Failed to allocate memory\n"); - return -1; - } - - entry->len = len; - entry->tspec.tv_sec = tspec->tv_sec; - entry->tspec.tv_nsec = tspec->tv_nsec; - memcpy(entry->nal, nal, entry->len); - - STAILQ_INSERT_TAIL(&nals, entry, entries); - - /* If this was the first entry inserted onto the queue, we need to arm - * the timer. - */ - if (STAILQ_FIRST(&nals) == entry) { - int res; - - res = arm_timer(fd, tspec); - if (res < 0) { - STAILQ_REMOVE(&nals, entry, nal_entry, entries); - free(entry); - return -1; - } - } - - return 0; + struct nal_entry *entry; + + entry = malloc(sizeof(*entry)); + if (!entry) { + fprintf(stderr, "Failed to allocate memory\n"); + return -1; + } + + entry->len = len; + entry->tspec.tv_sec = tspec->tv_sec; + entry->tspec.tv_nsec = tspec->tv_nsec; + memcpy(entry->nal, nal, entry->len); + + STAILQ_INSERT_TAIL(&nals, entry, entries); + + /* If this was the first entry inserted onto the queue, we need to arm + * the timer. + */ + if (STAILQ_FIRST(&nals) == entry) { + int res; + + res = arm_timer(fd, tspec); + if (res < 0) { + STAILQ_REMOVE(&nals, entry, nal_entry, entries); + free(entry); + return -1; + } + } + + return 0; } -static bool is_valid_packet(struct avtp_stream_pdu *pdu) +static bool is_valid_packet(Avtp_Cvf_t* cvf) { - struct avtp_common_pdu *common = (struct avtp_common_pdu *) pdu; - uint64_t val64; - uint32_t val32; - int res; - - res = avtp_pdu_get(common, AVTP_FIELD_SUBTYPE, &val32); - if (res < 0) { - fprintf(stderr, "Failed to get subtype field: %d\n", res); - return false; - } - if (val32 != AVTP_SUBTYPE_CVF) { - fprintf(stderr, "Subtype mismatch: expected %u, got %u\n", - AVTP_SUBTYPE_CVF, val32); - return false; - } - - res = avtp_pdu_get(common, AVTP_FIELD_VERSION, &val32); - if (res < 0) { - fprintf(stderr, "Failed to get version field: %d\n", res); - return false; - } - if (val32 != 0) { - fprintf(stderr, "Version mismatch: expected %u, got %u\n", - 0, val32); - return false; - } - - res = avtp_cvf_pdu_get(pdu, AVTP_CVF_FIELD_TV, &val64); - if (res < 0) { - fprintf(stderr, "Failed to get tv field: %d\n", res); - return false; - } - if (val64 != 1) { - fprintf(stderr, "tv mismatch: expected %u, got %lu\n", - 1, val64); - return false; - } - - res = avtp_cvf_pdu_get(pdu, AVTP_CVF_FIELD_STREAM_ID, &val64); - if (res < 0) { - fprintf(stderr, "Failed to get stream ID field: %d\n", res); - return false; - } - if (val64 != STREAM_ID) { - fprintf(stderr, "Stream ID mismatch: expected %lu, got %lu\n", - STREAM_ID, val64); - return false; - } - - res = avtp_cvf_pdu_get(pdu, AVTP_CVF_FIELD_SEQ_NUM, &val64); - if (res < 0) { - fprintf(stderr, "Failed to get sequence num field: %d\n", res); - return false; - } - - if (val64 != expected_seq) { - /* If we have a sequence number mismatch, we simply log the - * issue and continue to process the packet. We don't want to - * invalidate it since it is a valid packet after all. - */ - fprintf(stderr, - "Sequence number mismatch: expected %u, got %lu\n", - expected_seq, val64); - expected_seq = val64; - } - - expected_seq++; - - res = avtp_cvf_pdu_get(pdu, AVTP_CVF_FIELD_FORMAT, &val64); - if (res < 0) { - fprintf(stderr, "Failed to get format field: %d\n", res); - return false; - } - if (val64 != AVTP_CVF_FORMAT_RFC) { - fprintf(stderr, "Format mismatch: expected %u, got %lu\n", - AVTP_CVF_FORMAT_RFC, val64); - return false; - } - - res = avtp_cvf_pdu_get(pdu, AVTP_CVF_FIELD_FORMAT_SUBTYPE, &val64); - if (res < 0) { - fprintf(stderr, "Failed to get format subtype field: %d\n", - res); - return false; - } - if (val64 != AVTP_CVF_FORMAT_SUBTYPE_H264) { - fprintf(stderr, "Format mismatch: expected %u, got %lu\n", - AVTP_CVF_FORMAT_SUBTYPE_H264, val64); - return false; - } - - return true; + uint64_t val; + int res; + + res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_SUBTYPE, &val); + if (res < 0) { + fprintf(stderr, "Failed to get subtype field: %d\n", res); + return false; + } + if (val != AVTP_SUBTYPE_CVF) { + fprintf(stderr, "Subtype mismatch: expected %u, got %"PRIu64"\n", AVTP_SUBTYPE_CVF, val); + return false; + } + + res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_VERSION, &val); + if (res < 0) { + fprintf(stderr, "Failed to get version field: %d\n", res); + return false; + } + if (val != 0) { + fprintf(stderr, "Version mismatch: expected %u, got %"PRIu64"\n", 0, val); + return false; + } + + res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_TV, &val); + if (res < 0) { + fprintf(stderr, "Failed to get tv field: %d\n", res); + return false; + } + if (val != 1) { + fprintf(stderr, "tv mismatch: expected %u, got %lu\n", + 1, val); + return false; + } + + res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_STREAM_ID, &val); + if (res < 0) { + fprintf(stderr, "Failed to get stream ID field: %d\n", res); + return false; + } + if (val != STREAM_ID) { + fprintf(stderr, "Stream ID mismatch: expected %lu, got %lu\n", + STREAM_ID, val); + return false; + } + + res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_SEQUENCE_NUM, &val); + if (res < 0) { + fprintf(stderr, "Failed to get sequence num field: %d\n", res); + return false; + } + + if (val != expected_seq) { + /* If we have a sequence number mismatch, we simply log the + * issue and continue to process the packet. We don't want to + * invalidate it since it is a valid packet after all. + */ + fprintf(stderr, + "Sequence number mismatch: expected %u, got %lu\n", + expected_seq, val); + expected_seq = val; + } + + expected_seq++; + + res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_FORMAT, &val); + if (res < 0) { + fprintf(stderr, "Failed to get format field: %d\n", res); + return false; + } + if (val != AVTP_CVF_FORMAT_RFC) { + fprintf(stderr, "Format mismatch: expected %u, got %lu\n", + AVTP_CVF_FORMAT_RFC, val); + return false; + } + + res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_FORMAT_SUBTYPE, &val); + if (res < 0) { + fprintf(stderr, "Failed to get format subtype field: %d\n", + res); + return false; + } + if (val != AVTP_CVF_FORMAT_SUBTYPE_H264) { + fprintf(stderr, "Format mismatch: expected %u, got %lu\n", + AVTP_CVF_FORMAT_SUBTYPE_H264, val); + return false; + } + + return true; } -static int get_h264_data_len(struct avtp_stream_pdu *pdu, - uint16_t *stream_data_len) +static int get_h264_data_len(Avtp_Cvf_t* cvfHeader, uint16_t *stream_data_len) { - int res; - uint64_t val; + int res; + uint64_t val; - res = avtp_cvf_pdu_get(pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, &val); - if (res < 0) { - fprintf(stderr, "Failed to get data_len field\n"); - return -1; - } - *stream_data_len = val - AVTP_H264_HEADER_LEN; + res = Avtp_Cvf_GetField(cvfHeader, AVTP_CVF_FIELD_STREAM_DATA_LENGTH, &val); + if (res < 0) { + fprintf(stderr, "Failed to get data_len field\n"); + return -1; + } + *stream_data_len = val - AVTP_H264_HEADER_LEN; - return 0; + return 0; } static int new_packet(int sk_fd, int timer_fd) { - int res; - ssize_t n; - uint16_t h264_data_len; - uint64_t avtp_time; - struct timespec tspec; - struct avtp_stream_pdu *pdu = alloca(MAX_PDU_SIZE); - struct avtp_cvf_h264_payload *h264_pay = - (struct avtp_cvf_h264_payload *)pdu->avtp_payload; - - memset(pdu, 1, MAX_PDU_SIZE); - - n = recv(sk_fd, pdu, MAX_PDU_SIZE, 0); - if (n < 0 || n > MAX_PDU_SIZE) { - perror("Failed to receive data"); - return -1; - } - - if (!is_valid_packet(pdu)) { - fprintf(stderr, "Dropping packet\n"); - return 0; - } - - res = avtp_cvf_pdu_get(pdu, AVTP_CVF_FIELD_TIMESTAMP, &avtp_time); - if (res < 0) { - fprintf(stderr, "Failed to get AVTP time from PDU\n"); - return -1; - } - - res = get_presentation_time(avtp_time, &tspec); - if (res < 0) - return -1; - - res = get_h264_data_len(pdu, &h264_data_len); - if (res < 0) - return -1; - - res = schedule_nal(timer_fd, &tspec, h264_pay->h264_data, - h264_data_len); - if (res < 0) - return -1; - - return 0; + int res; + ssize_t n; + uint16_t h264_data_len; + uint64_t avtp_time; + struct timespec tspec; + Avtp_Cvf_t* cvfHeader = alloca(MAX_PDU_SIZE); + Avtp_H264_t* h264Header = (Avtp_H264_t*)(&cvfHeader->payload); + uint8_t* h264Payload = (uint8_t*)(&h264Header->payload); + + memset(cvfHeader, 1, MAX_PDU_SIZE); + + n = recv(sk_fd, cvfHeader, MAX_PDU_SIZE, 0); + if (n < 0 || n > MAX_PDU_SIZE) { + perror("Failed to receive data"); + return -1; + } + + if (!is_valid_packet(cvfHeader)) { + fprintf(stderr, "Dropping packet\n"); + return 0; + } + + res = Avtp_Cvf_GetField(cvfHeader, AVTP_CVF_FIELD_AVTP_TIMESTAMP, &avtp_time); + if (res < 0) { + fprintf(stderr, "Failed to get AVTP time from PDU\n"); + return -1; + } + + res = get_presentation_time(avtp_time, &tspec); + if (res < 0) + return -1; + + res = get_h264_data_len(cvfHeader, &h264_data_len); + if (res < 0) + return -1; + + res = schedule_nal(timer_fd, &tspec, h264Payload, h264_data_len); + if (res < 0) + return -1; + + return 0; } static int timeout(int fd) { - int res; - ssize_t n; - uint64_t expirations; - struct nal_entry *entry; + int res; + ssize_t n; + uint64_t expirations; + struct nal_entry *entry; - n = read(fd, &expirations, sizeof(uint64_t)); - if (n < 0) { - perror("Failed to read timerfd"); - return -1; - } + n = read(fd, &expirations, sizeof(uint64_t)); + if (n < 0) { + perror("Failed to read timerfd"); + return -1; + } - assert(expirations == 1); + assert(expirations == 1); - entry = STAILQ_FIRST(&nals); - assert(entry != NULL); + entry = STAILQ_FIRST(&nals); + assert(entry != NULL); - res = present_data(entry->nal, entry->len); - if (res < 0) - return -1; + res = present_data(entry->nal, entry->len); + if (res < 0) + return -1; - STAILQ_REMOVE_HEAD(&nals, entries); - free(entry); + STAILQ_REMOVE_HEAD(&nals, entries); + free(entry); - if (!STAILQ_EMPTY(&nals)) { - entry = STAILQ_FIRST(&nals); + if (!STAILQ_EMPTY(&nals)) { + entry = STAILQ_FIRST(&nals); - res = arm_timer(fd, &entry->tspec); - if (res < 0) - return -1; - } + res = arm_timer(fd, &entry->tspec); + if (res < 0) + return -1; + } - return 0; + return 0; } int main(int argc, char *argv[]) { - int sk_fd, timer_fd, res; - struct pollfd fds[2]; - - argp_parse(&argp, argc, argv, 0, NULL, NULL); - - STAILQ_INIT(&nals); - - sk_fd = create_listener_socket(ifname, macaddr, ETH_P_TSN); - if (sk_fd < 0) - return 1; - - timer_fd = timerfd_create(CLOCK_REALTIME, 0); - if (timer_fd < 0) { - close(sk_fd); - return 1; - } - - fds[0].fd = sk_fd; - fds[0].events = POLLIN; - fds[1].fd = timer_fd; - fds[1].events = POLLIN; - - while (1) { - res = poll(fds, 2, -1); - if (res < 0) { - perror("Failed to poll() fds"); - goto err; - } - - if (fds[0].revents & POLLIN) { - res = new_packet(sk_fd, timer_fd); - if (res < 0) - goto err; - } - - if (fds[1].revents & POLLIN) { - res = timeout(timer_fd); - if (res < 0) - goto err; - } - } - - return 0; + int sk_fd, timer_fd, res; + struct pollfd fds[2]; + + argp_parse(&argp, argc, argv, 0, NULL, NULL); + + STAILQ_INIT(&nals); + + sk_fd = create_listener_socket(ifname, macaddr, ETH_P_TSN); + if (sk_fd < 0) + return 1; + + timer_fd = timerfd_create(CLOCK_REALTIME, 0); + if (timer_fd < 0) { + close(sk_fd); + return 1; + } + + fds[0].fd = sk_fd; + fds[0].events = POLLIN; + fds[1].fd = timer_fd; + fds[1].events = POLLIN; + + while (1) { + res = poll(fds, 2, -1); + if (res < 0) { + perror("Failed to poll() fds"); + goto err; + } + + if (fds[0].revents & POLLIN) { + res = new_packet(sk_fd, timer_fd); + if (res < 0) + goto err; + } + + if (fds[1].revents & POLLIN) { + res = timeout(timer_fd); + if (res < 0) + goto err; + } + } + + return 0; err: - close(sk_fd); - close(timer_fd); - return 1; + close(sk_fd); + close(timer_fd); + return 1; } diff --git a/examples/cvf/cvf-talker.c b/examples/cvf/cvf-talker.c index f10ff9e..b86c555 100644 --- a/examples/cvf/cvf-talker.c +++ b/examples/cvf/cvf-talker.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, COVESA * Copyright (c) 2019, Intel Corporation * * Redistribution and use in source and binary forms, with or without @@ -9,9 +10,9 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * * Neither the name of COVESA, Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -23,6 +24,8 @@ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ /* CVF Talker example. @@ -73,15 +76,16 @@ #include #include "avtp.h" -#include "avtp_cvf.h" -#include "common.h" +#include "avtp/cvf/Cvf.h" +#include "avtp/cvf/H264.h" +#include "examples/common.h" #include "avtp/CommonHeader.h" -#define STREAM_ID 0xAABBCCDDEEFF0001 -#define DATA_LEN 1400 -#define AVTP_H264_HEADER_LEN (sizeof(uint32_t)) -#define AVTP_FULL_HEADER_LEN (sizeof(struct avtp_stream_pdu) + AVTP_H264_HEADER_LEN) -#define MAX_PDU_SIZE (AVTP_FULL_HEADER_LEN + DATA_LEN) +#define STREAM_ID 0xAABBCCDDEEFF0001 +#define DATA_LEN 1400 +#define AVTP_H264_HEADER_LEN (sizeof(Avtp_H264_t)) +#define AVTP_FULL_HEADER_LEN (sizeof(Avtp_Cvf_t) + sizeof(Avtp_H264_t)) +#define MAX_PDU_SIZE (AVTP_FULL_HEADER_LEN + DATA_LEN) static char ifname[IFNAMSIZ]; static uint8_t macaddr[ETH_ALEN]; @@ -96,247 +100,217 @@ static uint8_t seq_num; enum process_result {PROCESS_OK, PROCESS_NONE, PROCESS_ERROR}; static struct argp_option options[] = { - {"dst-addr", 'd', "MACADDR", 0, "Stream Destination MAC address" }, - {"ifname", 'i', "IFNAME", 0, "Network Interface" }, - {"max-transit-time", 'm', "MSEC", 0, "Maximum Transit Time in ms" }, - {"prio", 'p', "NUM", 0, "SO_PRIORITY to be set in socket" }, - { 0 } + {"dst-addr", 'd', "MACADDR", 0, "Stream Destination MAC address" }, + {"ifname", 'i', "IFNAME", 0, "Network Interface" }, + {"max-transit-time", 'm', "MSEC", 0, "Maximum Transit Time in ms" }, + {"prio", 'p', "NUM", 0, "SO_PRIORITY to be set in socket" }, + { 0 } }; static error_t parser(int key, char *arg, struct argp_state *state) { - int res; - - switch (key) { - case 'd': - res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", - &macaddr[0], &macaddr[1], &macaddr[2], - &macaddr[3], &macaddr[4], &macaddr[5]); - if (res != 6) { - fprintf(stderr, "Invalid address\n"); - exit(EXIT_FAILURE); - } - - break; - case 'i': - strncpy(ifname, arg, sizeof(ifname) - 1); - break; - case 'm': - max_transit_time = atoi(arg); - break; - case 'p': - priority = atoi(arg); - break; - } - - return 0; + int res; + + switch (key) { + case 'd': + res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &macaddr[0], &macaddr[1], &macaddr[2], + &macaddr[3], &macaddr[4], &macaddr[5]); + if (res != 6) { + fprintf(stderr, "Invalid address\n"); + exit(EXIT_FAILURE); + } + + break; + case 'i': + strncpy(ifname, arg, sizeof(ifname) - 1); + break; + case 'm': + max_transit_time = atoi(arg); + break; + case 'p': + priority = atoi(arg); + break; + } + + return 0; } static struct argp argp = { options, parser }; -static int init_pdu(struct avtp_stream_pdu *pdu) +static int init_pdu(Avtp_Cvf_t* cvf) { - int res; - - res = avtp_cvf_pdu_init(pdu, AVTP_CVF_FORMAT_SUBTYPE_H264); - if (res < 0) - return -1; - - res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_TV, 1); - if (res < 0) - return -1; - - res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID); - if (res < 0) - return -1; - - /* Just state that all data is part of the frame (M=1) */ - res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_M, 1); - if (res < 0) - return -1; - - /* No H.264 timestamp now */ - res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 0); - if (res < 0) - return -1; - - /* No H.264 timestamp means no PTV */ - res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_H264_PTV, 0); - if (res < 0) - return -1; - - return 0; + Avtp_Cvf_Init(cvf); + Avtp_Cvf_SetField(cvf, AVTP_CVF_FIELD_FORMAT_SUBTYPE, AVTP_CVF_FORMAT_SUBTYPE_H264); + Avtp_Cvf_SetField(cvf, AVTP_CVF_FIELD_TV, 1); + Avtp_Cvf_SetField(cvf, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID); + Avtp_Cvf_SetField(cvf, AVTP_CVF_FIELD_M, 1); + Avtp_Cvf_SetField(cvf, AVTP_CVF_FIELD_PTV, 0); + + Avtp_H264_t* h264 = (Avtp_H264_t*)(&cvf->payload); + Avtp_H264_Init(h264); + Avtp_H264_SetField(h264, AVTP_H264_FIELD_TIMESTAMP, 0); + + return 0; } static ssize_t fill_buffer(void) { - ssize_t n; + ssize_t n; - n = read(STDIN_FILENO, buffer + buffer_level, - sizeof(buffer) - buffer_level); - if (n < 0) { - perror("Could not read from standard input"); - } + n = read(STDIN_FILENO, buffer + buffer_level, + sizeof(buffer) - buffer_level); + if (n < 0) { + perror("Could not read from standard input"); + } - buffer_level += n; + buffer_level += n; - return n; + return n; } static ssize_t start_code_position(size_t offset) { - assert(offset < buffer_level); - - /* Simplified Boyer-Moore, inspired by gstreamer */ - while (offset < buffer_level - 2) { - if (buffer[offset + 2] == 0x1) { - if (buffer[offset] == 0x0 && buffer[offset + 1] == 0x0) - return offset; - offset += 3; - } else if (buffer[offset + 2] == 0x0) { - offset++; - } else { - offset += 3; - } - } - - return -1; + assert(offset < buffer_level); + + /* Simplified Boyer-Moore, inspired by gstreamer */ + while (offset < buffer_level - 2) { + if (buffer[offset + 2] == 0x1) { + if (buffer[offset] == 0x0 && buffer[offset + 1] == 0x0) + return offset; + offset += 3; + } else if (buffer[offset + 2] == 0x0) { + offset++; + } else { + offset += 3; + } + } + + return -1; } -static int prepare_packet(struct avtp_stream_pdu *pdu, char *nal_data, - size_t nal_data_len) +static int prepare_packet(Avtp_Cvf_t* cvfHeader, char *nal_data, size_t nal_data_len) { - int res; - uint32_t avtp_time; - struct avtp_cvf_h264_payload *h264_pay = - (struct avtp_cvf_h264_payload *) pdu->avtp_payload; - - res = calculate_avtp_time(&avtp_time, max_transit_time); - if (res < 0) { - fprintf(stderr, "Failed to calculate avtp time\n"); - return -1; - } - - res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_TIMESTAMP, - avtp_time); - if (res < 0) - return -1; - - res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_SEQ_NUM, seq_num++); - if (res < 0) - return -1; - - /* Stream data len includes AVTP H264 header, as this is part - * of the payload too*/ - res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, - nal_data_len + AVTP_H264_HEADER_LEN); - if (res < 0) - return -1; - - memcpy(h264_pay->h264_data, nal_data, nal_data_len); - - return 0; + int res; + uint32_t avtp_time; + Avtp_H264_t* h264Header = (Avtp_H264_t*)(&cvfHeader->payload); + uint8_t* h264Payload = (uint8_t*)(&h264Header->payload); + + res = calculate_avtp_time(&avtp_time, max_transit_time); + if (res < 0) { + fprintf(stderr, "Failed to calculate avtp time\n"); + return -1; + } + + Avtp_Cvf_SetField(cvfHeader, AVTP_CVF_FIELD_AVTP_TIMESTAMP, avtp_time); + Avtp_Cvf_SetField(cvfHeader, AVTP_CVF_FIELD_SEQUENCE_NUM, seq_num++); + Avtp_Cvf_SetField(cvfHeader, AVTP_CVF_FIELD_STREAM_DATA_LENGTH, nal_data_len + AVTP_H264_HEADER_LEN); + + memcpy(h264Payload, nal_data, nal_data_len); + + return 0; } -static int process_nal(struct avtp_stream_pdu *pdu, bool process_last, - size_t *nal_len) +static int process_nal(Avtp_Cvf_t* pdu, bool process_last, + size_t* nal_len) { - int res; - ssize_t start, end; - - *nal_len = 0; - - start = start_code_position(0); - if (start == -1) { - fprintf(stderr, "Unable to find NAL start\n"); - return PROCESS_NONE; - } - /* Now, let's find where the next starts. This is where current ends */ - end = start_code_position(start + 1); - if (end == -1) { - if (process_last == false) { - return PROCESS_NONE; - } else { - end = buffer_level; - } - } - - *nal_len = end - start; - if (*nal_len > DATA_LEN) { - fprintf(stderr, "NAL length bigger than expected. Expected %u, " - "found %zd\n", DATA_LEN, *nal_len); - goto err; - } - - /* Sets AVTP packet headers and content - the NAL unit */ - res = prepare_packet(pdu, &buffer[start], *nal_len); - if (res < 0) { - goto err; - } - - /* Finally, let's offset any remaining data on the buffer to the - * beginning. Not really efficient, but keep things simple */ - memmove(buffer, buffer + end, buffer_level - end); - buffer_level -= end; - - return PROCESS_OK; + int res; + ssize_t start, end; + + *nal_len = 0; + + start = start_code_position(0); + if (start == -1) { + fprintf(stderr, "Unable to find NAL start\n"); + return PROCESS_NONE; + } + /* Now, let's find where the next starts. This is where current ends */ + end = start_code_position(start + 1); + if (end == -1) { + if (process_last == false) { + return PROCESS_NONE; + } else { + end = buffer_level; + } + } + + *nal_len = end - start; + if (*nal_len > DATA_LEN) { + fprintf(stderr, "NAL length bigger than expected. Expected %u, " + "found %zd\n", DATA_LEN, *nal_len); + goto err; + } + + /* Sets AVTP packet headers and content - the NAL unit */ + res = prepare_packet(pdu, &buffer[start], *nal_len); + if (res < 0) { + goto err; + } + + /* Finally, let's offset any remaining data on the buffer to the + * beginning. Not really efficient, but keep things simple */ + memmove(buffer, buffer + end, buffer_level - end); + buffer_level -= end; + + return PROCESS_OK; err: - return PROCESS_ERROR; + return PROCESS_ERROR; } int main(int argc, char *argv[]) { - int fd, res; - struct sockaddr_ll sk_addr; - struct avtp_stream_pdu *pdu = alloca(MAX_PDU_SIZE); - - argp_parse(&argp, argc, argv, 0, NULL, NULL); - - fd = create_talker_socket(priority); - if (fd < 0) - return 1; - - res = setup_socket_address(fd, ifname, macaddr, ETH_P_TSN, &sk_addr); - if (res < 0) - goto err; - - res = init_pdu(pdu); - if (res < 0) - goto err; - - while (1) { - ssize_t n; - bool end = false; - - n = fill_buffer(); - if (n == 0) - end = true; - - while (buffer_level > 0) { - enum process_result pr = - process_nal(pdu, end, (size_t *)&n); - if (pr == PROCESS_ERROR) - goto err; - if (pr == PROCESS_NONE) - break; - - n = sendto(fd, pdu, AVTP_FULL_HEADER_LEN + n, 0, - (struct sockaddr *) &sk_addr, sizeof(sk_addr)); - if (n < 0) { - perror("Failed to send data"); - goto err; - } - } - - if (end) - break; - } - - close(fd); - return 0; + int fd, res; + struct sockaddr_ll sk_addr; + uint8_t* pdu = alloca(MAX_PDU_SIZE); + Avtp_Cvf_t* cvf = (Avtp_Cvf_t*)pdu; + + argp_parse(&argp, argc, argv, 0, NULL, NULL); + + fd = create_talker_socket(priority, 0); + if (fd < 0) + return 1; + + res = setup_socket_address(fd, ifname, macaddr, ETH_P_TSN, &sk_addr); + if (res < 0) + goto err; + + res = init_pdu(cvf); + if (res < 0) + goto err; + + while (1) { + ssize_t n; + bool end = false; + + n = fill_buffer(); + if (n == 0) + end = true; + + while (buffer_level > 0) { + enum process_result pr = + process_nal(cvf, end, (size_t *)&n); + if (pr == PROCESS_ERROR) + goto err; + if (pr == PROCESS_NONE) + break; + + n = sendto(fd, pdu, AVTP_FULL_HEADER_LEN + n, 0, + (struct sockaddr *) &sk_addr, sizeof(sk_addr)); + if (n < 0) { + perror("Failed to send data"); + goto err; + } + } + + if (end) + break; + } + + close(fd); + return 0; err: - close(fd); - return 1; + close(fd); + return 1; } diff --git a/include/avtp/cvf/Cvf.h b/include/avtp/cvf/Cvf.h new file mode 100644 index 0000000..1f10e8e --- /dev/null +++ b/include/avtp/cvf/Cvf.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024, COVESA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of COVESA, Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#pragma once + +#include + +#include "avtp/Utils.h" + +#define AVTP_CVF_HEADER_LEN (6 * AVTP_QUADLET_SIZE) + +typedef struct Avtp_Cvf { + uint8_t header[AVTP_CVF_HEADER_LEN]; + uint8_t payload[0]; +} Avtp_Cvf_t; + +typedef enum Avtp_CvfField { + /* CVF header fields */ + AVTP_CVF_FIELD_SUBTYPE, + AVTP_CVF_FIELD_SV, + AVTP_CVF_FIELD_VERSION, + AVTP_CVF_FIELD_MR, + AVTP_CVF_FIELD_RESERVED, + AVTP_CVF_FIELD_TV, + AVTP_CVF_FIELD_SEQUENCE_NUM, + AVTP_CVF_FIELD_RESERVED_2, + AVTP_CVF_FIELD_TU, + AVTP_CVF_FIELD_STREAM_ID, + AVTP_CVF_FIELD_AVTP_TIMESTAMP, + AVTP_CVF_FIELD_FORMAT, + AVTP_CVF_FIELD_FORMAT_SUBTYPE, + AVTP_CVF_FIELD_RESERVED_3, + AVTP_CVF_FIELD_STREAM_DATA_LENGTH, + AVTP_CVF_FIELD_RESERVED_4, + AVTP_CVF_FIELD_PTV, + AVTP_CVF_FIELD_M, + AVTP_CVF_FIELD_EVT, + AVTP_CVF_FIELD_RESERVED_5, + /* Count number of fields for bound checks */ + AVTP_CVF_FIELD_MAX +} Avtp_CvfField_t; + +typedef enum Avtp_CvfFormat { + AVTP_CVF_FORMAT_RFC = 0x2 +} Avtp_CvfFormat_t; + +typedef enum Avtp_CvfFormatSubtype { + AVTP_CVF_FORMAT_SUBTYPE_MJPEG = 0x0, + AVTP_CVF_FORMAT_SUBTYPE_H264 = 0x1, + AVTP_CVF_FORMAT_SUBTYPE_JPEG2000 = 0x2 +} Avtp_CvfFormatSubtype_t; + +int Avtp_Cvf_Init(Avtp_Cvf_t* pdu); + +int Avtp_Cvf_GetField(Avtp_Cvf_t* pdu, Avtp_CvfField_t field, uint64_t* value); + +int Avtp_Cvf_SetField(Avtp_Cvf_t* pdu, Avtp_CvfField_t field, uint64_t value); + +/****************************************************************************** + * Legacy API (deprecated) + *****************************************************************************/ + +/** + * @deprecated + */ +int avtp_cvf_pdu_get(void* pdu, Avtp_CvfField_t field, uint64_t *val); + +/** + * @deprecated + */ +int avtp_cvf_pdu_set(void* pdu, Avtp_CvfField_t field, uint64_t val); + +/** + * @deprecated + */ +int avtp_cvf_pdu_init(void* pdu, uint8_t format_subtype); + diff --git a/include/avtp/cvf/H264.h b/include/avtp/cvf/H264.h new file mode 100644 index 0000000..ca59a96 --- /dev/null +++ b/include/avtp/cvf/H264.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024, COVESA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of COVESA, Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#pragma once + +#include + +#include "avtp/Utils.h" + +#define AVTP_H246_HEADER_LEN (1 * AVTP_QUADLET_SIZE) + +typedef struct Avtp_H264 { + uint8_t header[AVTP_H246_HEADER_LEN]; + uint8_t payload[0]; +} Avtp_H264_t; + +typedef enum Avtp_H264Field { + /* H264 header fields */ + AVTP_H264_FIELD_TIMESTAMP, + /* Count number of fields for bound checks */ + AVTP_H264_FIELD_MAX, +} Avtp_H264Field_t; + +int Avtp_H264_Init(Avtp_H264_t* pdu); + +int Avtp_H264_GetField(Avtp_H264_t* pdu, Avtp_H264Field_t field, uint64_t* value); + +int Avtp_H264_SetField(Avtp_H264_t* pdu, Avtp_H264Field_t field, uint64_t value); diff --git a/include/avtp/cvf/Jpeg2000.h b/include/avtp/cvf/Jpeg2000.h new file mode 100644 index 0000000..7e5b3d0 --- /dev/null +++ b/include/avtp/cvf/Jpeg2000.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024, COVESA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of COVESA, Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#pragma once + +#include + +#include "avtp/Utils.h" + +#define AVTP_JPEG2000_HEADER_LEN (2 * AVTP_QUADLET_SIZE) + +typedef struct Avtp_Jpeg2000 { + uint8_t header[AVTP_JPEG2000_HEADER_LEN]; + uint8_t payload[0]; +} Avtp_Jpeg2000_t; + +typedef enum Avtp_Jpeg2000Field { + /* MJPEG header fields */ + AVTP_JPEG2000_FIELD_TP, + AVTP_JPEG2000_FIELD_MHF, + AVTP_JPEG2000_FIELD_MH_ID, + AVTP_JPEG2000_FIELD_T, + AVTP_JPEG2000_FIELD_PRIORITY, + AVTP_JPEG2000_FIELD_TILE_NUMBER, + AVTP_JPEG2000_FIELD_RESERVED, + AVTP_JPEG2000_FIELD_FRAGMENT_OFFSET, + /* Count number of fields for bound checks */ + AVTP_JPEG2000_FIELD_MAX +} Avtp_Jpeg2000Field_t; + +int Avtp_Jpeg2000_Init(Avtp_Jpeg2000_t* pdu); + +int Avtp_Jpeg2000_GetField(Avtp_Jpeg2000_t* pdu, Avtp_Jpeg2000Field_t field, uint64_t* value); + +int Avtp_Jpeg2000_SetField(Avtp_Jpeg2000_t* pdu, Avtp_Jpeg2000Field_t field, uint64_t value); diff --git a/include/avtp/cvf/Mjpeg.h b/include/avtp/cvf/Mjpeg.h new file mode 100644 index 0000000..abeb10b --- /dev/null +++ b/include/avtp/cvf/Mjpeg.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024, COVESA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of COVESA, Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#pragma once + +#include + +#include "avtp/Utils.h" + +#define AVTP_MJPEG_HEADER_LEN (2 * AVTP_QUADLET_SIZE) + +typedef struct Avtp_Mjpeg { + uint8_t header[AVTP_MJPEG_HEADER_LEN]; + uint8_t payload[0]; +} Avtp_Mjpeg_t; + +typedef enum Avtp_MjpegField { + /* MJPEG header fields */ + AVTP_MJPEG_FIELD_TYPE_SPECIFIC, + AVTP_MJPEG_FIELD_FRAGMENT_OFFSET, + AVTP_MJPEG_FIELD_TYPE, + AVTP_MJPEG_FIELD_Q, + AVTP_MJPEG_FIELD_WIDTH, + AVTP_MJPEG_FIELD_HEIGHT, + /* Count number of fields for bound checks */ + AVTP_MJPEG_FIELD_MAX +} Avtp_MjpegField_t; + +int Avtp_Mjpeg_Init(Avtp_Mjpeg_t* pdu); + +int Avtp_Mjpeg_GetField(Avtp_Mjpeg_t* pdu, Avtp_MjpegField_t field, uint64_t* value); + +int Avtp_Mjpeg_SetField(Avtp_Mjpeg_t* pdu, Avtp_MjpegField_t field, uint64_t value); diff --git a/include/avtp_cvf.h b/include/avtp_cvf.h deleted file mode 100644 index f2c2887..0000000 --- a/include/avtp_cvf.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2019, Intel Corporation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* CVF 'format' field values. */ -#define AVTP_CVF_FORMAT_RFC 0x02 - -/* CVF 'format subtype' field values. */ -#define AVTP_CVF_FORMAT_SUBTYPE_MJPEG 0x00 -#define AVTP_CVF_FORMAT_SUBTYPE_H264 0x01 -#define AVTP_CVF_FORMAT_SUBTYPE_JPEG2000 0x02 - -enum avtp_cvf_field { - AVTP_CVF_FIELD_SV, - AVTP_CVF_FIELD_MR, - AVTP_CVF_FIELD_TV, - AVTP_CVF_FIELD_SEQ_NUM, - AVTP_CVF_FIELD_TU, - AVTP_CVF_FIELD_STREAM_ID, - AVTP_CVF_FIELD_TIMESTAMP, - AVTP_CVF_FIELD_STREAM_DATA_LEN, - AVTP_CVF_FIELD_FORMAT, - AVTP_CVF_FIELD_FORMAT_SUBTYPE, - AVTP_CVF_FIELD_M, - AVTP_CVF_FIELD_EVT, - AVTP_CVF_FIELD_H264_PTV, - AVTP_CVF_FIELD_H264_TIMESTAMP, - AVTP_CVF_FIELD_MAX, -}; - -struct avtp_cvf_h264_payload { - uint32_t h264_header; - uint8_t h264_data[0]; -} __attribute__((__packed__)); - -/* Get value of CVF AVTPDU field. - * @pdu: Pointer to PDU struct. - * @field: PDU field to be retrieved. - * @val: Pointer to variable which the retrieved value should be saved. - * - * Returns: - * 0: Success. - * -EINVAL: If any argument is invalid. - */ -int avtp_cvf_pdu_get(const struct avtp_stream_pdu *pdu, - enum avtp_cvf_field field, uint64_t *val); - -/* Set value of CVF AVTPDU field. - * @pdu: Pointer to PDU struct. - * @field: PDU field to be set. - * @val: Value to be set. - * - * Returns: - * 0: Success. - * -EINVAL: If any argument is invalid. - */ -int avtp_cvf_pdu_set(struct avtp_stream_pdu *pdu, enum avtp_cvf_field field, - uint64_t val); - -/* Initialize CVF AVTPDU. All AVTPDU fields are initialized with zero except - * 'subtype' (which is set to AVTP_SUBTYPE_CVF), 'sv' (which is set to 1), - * 'format' (which is set to AVTP_CVF_FORMAT_RFC) and 'format_subtype' (which is - * set to the `subtype` specified). - * @pdu: Pointer to PDU struct. - * @subtype: AVTP - * CVF Format Subtype of this AVTPDU. - * - * Return values: 0: Success. -EINVAL: If any argument is invalid. - */ -int avtp_cvf_pdu_init(struct avtp_stream_pdu *pdu, uint8_t subtype); - -#ifdef __cplusplus -} -#endif diff --git a/meson.build b/meson.build index 01cf6ea..bf4be5c 100644 --- a/meson.build +++ b/meson.build @@ -10,7 +10,6 @@ avtp_lib = library( 'open1722', [ 'src/avtp.c', - 'src/avtp_cvf.c', 'src/avtp_ieciidc.c', 'src/avtp_stream.c', @@ -28,6 +27,10 @@ avtp_lib = library( 'src/avtp/Udp.c', 'src/avtp/Rvf.c', 'src/avtp/Crf.c', + 'src/avtp/cvf/Cvf.c', + 'src/avtp/cvf/H264.c', + 'src/avtp/cvf/Jpeg2000.c', + 'src/avtp/cvf/Mjpeg.c', ], version: meson.project_version(), include_directories: include_directories('include'), @@ -67,6 +70,14 @@ install_headers( subdir : 'avtp/aaf' ) +install_headers( + 'src/avtp/cvf/Cvf.c', + 'src/avtp/cvf/H264.c', + 'src/avtp/cvf/Jpeg2000.c', + 'src/avtp/cvf/Mjpeg.c', + subdir : 'avtp/cvf' +) + pkg = import('pkgconfig') pkg.generate(avtp_lib, description: 'AVTP packetization library', diff --git a/src/avtp/cvf/Cvf.c b/src/avtp/cvf/Cvf.c new file mode 100644 index 0000000..1e537dc --- /dev/null +++ b/src/avtp/cvf/Cvf.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2024, COVESA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of COVESA, Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include "avtp/cvf/Cvf.h" +#include "avtp/Utils.h" +#include "avtp/CommonHeader.h" + +static const Avtp_FieldDescriptor_t fieldDescriptors[AVTP_CVF_FIELD_MAX] = +{ + [AVTP_CVF_FIELD_SUBTYPE] = { .quadlet = 0, .offset = 0, .bits = 8 }, + [AVTP_CVF_FIELD_SV] = { .quadlet = 0, .offset = 8, .bits = 1 }, + [AVTP_CVF_FIELD_VERSION] = { .quadlet = 0, .offset = 9, .bits = 3 }, + [AVTP_CVF_FIELD_MR] = { .quadlet = 0, .offset = 12, .bits = 1 }, + [AVTP_CVF_FIELD_RESERVED] = { .quadlet = 0, .offset = 13, .bits = 2 }, + [AVTP_CVF_FIELD_TV] = { .quadlet = 0, .offset = 15, .bits = 1 }, + [AVTP_CVF_FIELD_SEQUENCE_NUM] = { .quadlet = 0, .offset = 16, .bits = 8 }, + [AVTP_CVF_FIELD_RESERVED_2] = { .quadlet = 0, .offset = 24, .bits = 7 }, + [AVTP_CVF_FIELD_TU] = { .quadlet = 0, .offset = 31, .bits = 1 }, + [AVTP_CVF_FIELD_STREAM_ID] = { .quadlet = 1, .offset = 0, .bits = 64 }, + [AVTP_CVF_FIELD_AVTP_TIMESTAMP] = { .quadlet = 3, .offset = 0, .bits = 32 }, + [AVTP_CVF_FIELD_FORMAT] = { .quadlet = 4, .offset = 0, .bits = 8 }, + [AVTP_CVF_FIELD_FORMAT_SUBTYPE] = { .quadlet = 4, .offset = 8, .bits = 8 }, + [AVTP_CVF_FIELD_RESERVED_3] = { .quadlet = 4, .offset = 16, .bits = 16 }, + [AVTP_CVF_FIELD_STREAM_DATA_LENGTH] = { .quadlet = 5, .offset = 0, .bits = 16 }, + [AVTP_CVF_FIELD_RESERVED_4] = { .quadlet = 5, .offset = 16, .bits = 2 }, + [AVTP_CVF_FIELD_PTV] = { .quadlet = 5, .offset = 18, .bits = 1 }, + [AVTP_CVF_FIELD_M] = { .quadlet = 5, .offset = 19, .bits = 1 }, + [AVTP_CVF_FIELD_EVT] = { .quadlet = 5, .offset = 20, .bits = 4 }, + [AVTP_CVF_FIELD_RESERVED_5] = { .quadlet = 5, .offset = 24, .bits = 8 }, +}; + +int Avtp_Cvf_Init(Avtp_Cvf_t* pdu) +{ + if (pdu == NULL) return -EINVAL; + + memset(pdu, 0, sizeof(Avtp_Cvf_t)); + + int ret; + ret = Avtp_Cvf_SetField(pdu, AVTP_CVF_FIELD_SUBTYPE, AVTP_SUBTYPE_CVF); + if (ret != 0) return ret; + ret = Avtp_Cvf_SetField(pdu, AVTP_CVF_FIELD_SV, 1); + if (ret != 0) return ret; + + return 0; +} + +int Avtp_Cvf_GetField(Avtp_Cvf_t* pdu, Avtp_CvfField_t field, uint64_t* value) +{ + return Avtp_GetField(fieldDescriptors, AVTP_CVF_FIELD_MAX, (uint8_t*)pdu, field, value); +} + +int Avtp_Cvf_SetField(Avtp_Cvf_t* pdu, Avtp_CvfField_t field, uint64_t value) +{ + return Avtp_SetField(fieldDescriptors, AVTP_CVF_FIELD_MAX, (uint8_t*)pdu, field, value); +} + +/****************************************************************************** + * Legacy API (deprecated) + *****************************************************************************/ + +int avtp_cvf_pdu_get(void* pdu, Avtp_CvfField_t field, uint64_t *val) +{ + return Avtp_Cvf_GetField((Avtp_Cvf_t*)pdu, field, val); +} + +int avtp_cvf_pdu_set(void* pdu, Avtp_CvfField_t field, uint64_t val) +{ + return Avtp_Cvf_SetField((Avtp_Cvf_t*)pdu, field, val); +} + +int avtp_cvf_pdu_init(void* pdu, uint8_t format_subtype) +{ + int ret; + ret = Avtp_Cvf_Init((Avtp_Cvf_t*)pdu); + if (ret != 0) return ret; + ret = Avtp_Cvf_SetField(pdu, AVTP_CVF_FIELD_FORMAT_SUBTYPE, format_subtype); + if (ret != 0) return ret; + ret = Avtp_Cvf_SetField(pdu, AVTP_CVF_FIELD_FORMAT, AVTP_CVF_FORMAT_RFC); + if (ret != 0) return ret; + + return 0; +} diff --git a/src/avtp/cvf/H264.c b/src/avtp/cvf/H264.c new file mode 100644 index 0000000..20963de --- /dev/null +++ b/src/avtp/cvf/H264.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024, COVESA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of COVESA, Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include "avtp/cvf/H264.h" +#include "avtp/Utils.h" +#include "avtp/CommonHeader.h" + +static const Avtp_FieldDescriptor_t fieldDescriptors[AVTP_H264_FIELD_MAX] = +{ + [AVTP_H264_FIELD_TIMESTAMP] = { .quadlet = 0, .offset = 0, .bits = 32 }, +}; + +int Avtp_H264_Init(Avtp_H264_t* pdu) +{ + if (pdu == NULL) return -EINVAL; + memset(pdu, 0, sizeof(Avtp_H264_t)); + return 0; +} + +int Avtp_H264_GetField(Avtp_H264_t* pdu, Avtp_H264Field_t field, uint64_t* value) +{ + return Avtp_GetField(fieldDescriptors, AVTP_H264_FIELD_MAX, (uint8_t*)pdu, field, value); +} + +int Avtp_H264_SetField(Avtp_H264_t* pdu, Avtp_H264Field_t field, uint64_t value) +{ + return Avtp_SetField(fieldDescriptors, AVTP_H264_FIELD_MAX, (uint8_t*)pdu, field, value); +} diff --git a/src/avtp/cvf/Jpeg2000.c b/src/avtp/cvf/Jpeg2000.c new file mode 100644 index 0000000..1cc0e9f --- /dev/null +++ b/src/avtp/cvf/Jpeg2000.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024, COVESA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of COVESA, Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include "avtp/cvf/Jpeg2000.h" +#include "avtp/Utils.h" +#include "avtp/CommonHeader.h" + +static const Avtp_FieldDescriptor_t fieldDescriptors[AVTP_JPEG2000_FIELD_MAX] = +{ + [AVTP_JPEG2000_FIELD_TP] = { .quadlet = 0, .offset = 0, .bits = 2 }, + [AVTP_JPEG2000_FIELD_MHF] = { .quadlet = 0, .offset = 2, .bits = 2 }, + [AVTP_JPEG2000_FIELD_MH_ID] = { .quadlet = 0, .offset = 4, .bits = 3 }, + [AVTP_JPEG2000_FIELD_T] = { .quadlet = 0, .offset = 7, .bits = 1 }, + [AVTP_JPEG2000_FIELD_PRIORITY] = { .quadlet = 0, .offset = 8, .bits = 8 }, + [AVTP_JPEG2000_FIELD_TILE_NUMBER] = { .quadlet = 0, .offset = 16, .bits = 16 }, + [AVTP_JPEG2000_FIELD_RESERVED] = { .quadlet = 1, .offset = 0, .bits = 8 }, + [AVTP_JPEG2000_FIELD_FRAGMENT_OFFSET] = { .quadlet = 1, .offset = 8, .bits = 24 }, +}; + +int Avtp_Jpeg2000_Init(Avtp_Jpeg2000_t* pdu) +{ + if (pdu == NULL) return -EINVAL; + memset(pdu, 0, sizeof(Avtp_Jpeg2000_t)); + return 0; +} + +int Avtp_Jpeg2000_GetField(Avtp_Jpeg2000_t* pdu, Avtp_Jpeg2000Field_t field, uint64_t* value) +{ + return Avtp_GetField(fieldDescriptors, AVTP_JPEG2000_FIELD_MAX, (uint8_t*)pdu, field, value); +} + +int Avtp_Jpeg2000_SetField(Avtp_Jpeg2000_t* pdu, Avtp_Jpeg2000Field_t field, uint64_t value) +{ + return Avtp_SetField(fieldDescriptors, AVTP_JPEG2000_FIELD_MAX, (uint8_t*)pdu, field, value); +} diff --git a/src/avtp/cvf/Mjpeg.c b/src/avtp/cvf/Mjpeg.c new file mode 100644 index 0000000..a108d98 --- /dev/null +++ b/src/avtp/cvf/Mjpeg.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024, COVESA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of COVESA, Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include "avtp/cvf/Mjpeg.h" +#include "avtp/Utils.h" +#include "avtp/CommonHeader.h" + +static const Avtp_FieldDescriptor_t fieldDescriptors[AVTP_MJPEG_FIELD_MAX] = +{ + [AVTP_MJPEG_FIELD_TYPE_SPECIFIC] = { .quadlet = 0, .offset = 0, .bits = 8 }, + [AVTP_MJPEG_FIELD_FRAGMENT_OFFSET] = { .quadlet = 0, .offset = 8, .bits = 24 }, + [AVTP_MJPEG_FIELD_TYPE] = { .quadlet = 1, .offset = 0, .bits = 8 }, + [AVTP_MJPEG_FIELD_Q] = { .quadlet = 1, .offset = 8, .bits = 8 }, + [AVTP_MJPEG_FIELD_WIDTH] = { .quadlet = 1, .offset = 16, .bits = 8 }, + [AVTP_MJPEG_FIELD_HEIGHT] = { .quadlet = 1, .offset = 24, .bits = 8 }, +}; + +int Avtp_Mjpeg_Init(Avtp_Mjpeg_t* pdu) +{ + if (pdu == NULL) return -EINVAL; + memset(pdu, 0, sizeof(Avtp_Mjpeg_t)); + return 0; +} + +int Avtp_Mjpeg_GetField(Avtp_Mjpeg_t* pdu, Avtp_MjpegField_t field, uint64_t* value) +{ + return Avtp_GetField(fieldDescriptors, AVTP_MJPEG_FIELD_MAX, (uint8_t*)pdu, field, value); +} + +int Avtp_Mjpeg_SetField(Avtp_Mjpeg_t* pdu, Avtp_MjpegField_t field, uint64_t value) +{ + return Avtp_SetField(fieldDescriptors, AVTP_MJPEG_FIELD_MAX, (uint8_t*)pdu, field, value); +} diff --git a/src/avtp_cvf.c b/src/avtp_cvf.c deleted file mode 100644 index f91bfbd..0000000 --- a/src/avtp_cvf.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (c) 2019, Intel Corporation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Intel Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include - -#include "avtp.h" -#include "avtp_cvf.h" -#include "avtp_stream.h" -#include "util.h" -#include "avtp/CommonHeader.h" - -#define SHIFT_FORMAT (31 - 7) -#define SHIFT_FORMAT_SUBTYPE (31 - 15) -#define SHIFT_M (31 - 19) -#define SHIFT_EVT (31 - 23) -#define SHIFT_PTV (31 - 18) - -#define MASK_FORMAT (BITMASK(8) << SHIFT_FORMAT) -#define MASK_FORMAT_SUBTYPE (BITMASK(8) << SHIFT_FORMAT_SUBTYPE) -#define MASK_M (BITMASK(1) << SHIFT_M) -#define MASK_EVT (BITMASK(4) << SHIFT_EVT) -#define MASK_PTV (BITMASK(1) << SHIFT_PTV) - -static int get_field_value(const struct avtp_stream_pdu *pdu, - enum avtp_cvf_field field, uint64_t *val) -{ - uint32_t bitmap, mask; - uint8_t shift; - - switch (field) { - case AVTP_CVF_FIELD_FORMAT: - mask = MASK_FORMAT; - shift = SHIFT_FORMAT; - bitmap = ntohl(pdu->format_specific); - break; - case AVTP_CVF_FIELD_FORMAT_SUBTYPE: - mask = MASK_FORMAT_SUBTYPE; - shift = SHIFT_FORMAT_SUBTYPE; - bitmap = ntohl(pdu->format_specific); - break; - case AVTP_CVF_FIELD_M: - mask = MASK_M; - shift = SHIFT_M; - bitmap = ntohl(pdu->packet_info); - break; - case AVTP_CVF_FIELD_EVT: - mask = MASK_EVT; - shift = SHIFT_EVT; - bitmap = ntohl(pdu->packet_info); - break; - case AVTP_CVF_FIELD_H264_PTV: - mask = MASK_PTV; - shift = SHIFT_PTV; - bitmap = ntohl(pdu->packet_info); - break; - default: - return -EINVAL; - } - - *val = BITMAP_GET_VALUE(bitmap, mask, shift); - - return 0; -} - -int avtp_cvf_pdu_get(const struct avtp_stream_pdu *pdu, - enum avtp_cvf_field field, uint64_t *val) -{ - int res; - - if (!pdu || !val) - return -EINVAL; - - switch (field) { - case AVTP_CVF_FIELD_SV: - case AVTP_CVF_FIELD_MR: - case AVTP_CVF_FIELD_TV: - case AVTP_CVF_FIELD_SEQ_NUM: - case AVTP_CVF_FIELD_TU: - case AVTP_CVF_FIELD_STREAM_DATA_LEN: - case AVTP_CVF_FIELD_TIMESTAMP: - case AVTP_CVF_FIELD_STREAM_ID: - res = avtp_stream_pdu_get(pdu, (enum avtp_stream_field) field, - val); - break; - case AVTP_CVF_FIELD_FORMAT: - case AVTP_CVF_FIELD_FORMAT_SUBTYPE: - case AVTP_CVF_FIELD_M: - case AVTP_CVF_FIELD_EVT: - case AVTP_CVF_FIELD_H264_PTV: - res = get_field_value(pdu, field, val); - break; - case AVTP_CVF_FIELD_H264_TIMESTAMP: - { - /* This field lives on H.264 header, inside avtp_payload */ - struct avtp_cvf_h264_payload *pay = - (struct avtp_cvf_h264_payload *)pdu->avtp_payload; - *val = ntohl(pay->h264_header); - res = 0; - break; - } - default: - res = -EINVAL; - break; - } - - return res; -} - -static int set_field_value(struct avtp_stream_pdu *pdu, - enum avtp_cvf_field field, uint32_t val) -{ - uint32_t bitmap, mask; - uint8_t shift; - void *ptr; - - switch (field) { - case AVTP_CVF_FIELD_FORMAT: - mask = MASK_FORMAT; - shift = SHIFT_FORMAT; - ptr = &pdu->format_specific; - break; - case AVTP_CVF_FIELD_FORMAT_SUBTYPE: - mask = MASK_FORMAT_SUBTYPE; - shift = SHIFT_FORMAT_SUBTYPE; - ptr = &pdu->format_specific; - break; - case AVTP_CVF_FIELD_M: - mask = MASK_M; - shift = SHIFT_M; - ptr = &pdu->packet_info; - break; - case AVTP_CVF_FIELD_EVT: - mask = MASK_EVT; - shift = SHIFT_EVT; - ptr = &pdu->packet_info; - break; - case AVTP_CVF_FIELD_H264_PTV: - mask = MASK_PTV; - shift = SHIFT_PTV; - ptr = &pdu->packet_info; - break; - default: - return -EINVAL; - } - - bitmap = get_unaligned_be32(ptr); - - BITMAP_SET_VALUE(bitmap, val, mask, shift); - - put_unaligned_be32(bitmap, ptr); - - return 0; -} - -int avtp_cvf_pdu_set(struct avtp_stream_pdu *pdu, enum avtp_cvf_field field, - uint64_t val) -{ - int res; - - if (!pdu) - return -EINVAL; - - switch (field) { - case AVTP_CVF_FIELD_SV: - case AVTP_CVF_FIELD_MR: - case AVTP_CVF_FIELD_TV: - case AVTP_CVF_FIELD_SEQ_NUM: - case AVTP_CVF_FIELD_TU: - case AVTP_CVF_FIELD_STREAM_DATA_LEN: - case AVTP_CVF_FIELD_TIMESTAMP: - case AVTP_CVF_FIELD_STREAM_ID: - res = avtp_stream_pdu_set(pdu, (enum avtp_stream_field) field, - val); - break; - case AVTP_CVF_FIELD_FORMAT: - case AVTP_CVF_FIELD_FORMAT_SUBTYPE: - case AVTP_CVF_FIELD_M: - case AVTP_CVF_FIELD_EVT: - case AVTP_CVF_FIELD_H264_PTV: - res = set_field_value(pdu, field, val); - break; - case AVTP_CVF_FIELD_H264_TIMESTAMP: - { - /* This field lives on H.264 header, inside avtp_payload */ - struct avtp_cvf_h264_payload *pay = - (struct avtp_cvf_h264_payload *)pdu->avtp_payload; - pay->h264_header = htonl(val); - res = 0; - break; - } - default: - res = -EINVAL; - break; - } - - return res; -} - -int avtp_cvf_pdu_init(struct avtp_stream_pdu *pdu, uint8_t subtype) -{ - int res; - - if (!pdu) - return -EINVAL; - - if (subtype > AVTP_CVF_FORMAT_SUBTYPE_JPEG2000) - return -EINVAL; - - memset(pdu, 0, sizeof(struct avtp_stream_pdu)); - - res = avtp_pdu_set((struct avtp_common_pdu *) pdu, AVTP_FIELD_SUBTYPE, - AVTP_SUBTYPE_CVF); - if (res < 0) - return res; - - res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_SV, 1); - if (res < 0) - return res; - - res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_FORMAT, AVTP_CVF_FORMAT_RFC); - if (res < 0) - return res; - - res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_FORMAT_SUBTYPE, subtype); - if (res < 0) - return res; - - return 0; -} diff --git a/unit/test-cvf.c b/unit/test-cvf.c index 34151e5..e7c6af5 100644 --- a/unit/test-cvf.c +++ b/unit/test-cvf.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2019, Intel Corporation + * Copyright (c) 2024, COVESA * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,564 +35,544 @@ #include #include "avtp.h" -#include "avtp_cvf.h" +#include "avtp/cvf/Cvf.h" +#include "avtp/cvf/H264.h" static void cvf_get_field_null_pdu(void **state) { - int res; - uint64_t val = 1; + int res; + uint64_t val = 1; - res = avtp_cvf_pdu_get(NULL, AVTP_CVF_FIELD_SV, &val); + res = avtp_cvf_pdu_get(NULL, AVTP_CVF_FIELD_SV, &val); - assert_int_equal(res, -EINVAL); + assert_int_equal(res, -EINVAL); } static void cvf_get_field_null_val(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_SV, NULL); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_SV, NULL); - assert_int_equal(res, -EINVAL); + assert_int_equal(res, -EINVAL); } static void cvf_get_field_invalid_field(void **state) { - int res; - uint64_t val = 1; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val = 1; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_MAX, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_MAX, &val); - assert_int_equal(res, -EINVAL); + assert_int_equal(res, -EINVAL); } static void cvf_get_field_sv(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'sv' field to 1. */ - pdu.subtype_data = htonl(0x00800000); + /* Set 'sv' field to 1. */ + pdu.subtype_data = htonl(0x00800000); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_SV, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_SV, &val); - assert_int_equal(res, 0); - assert_true(val == 1); + assert_int_equal(res, 0); + assert_true(val == 1); } static void cvf_get_field_mr(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'mr' field to 1. */ - pdu.subtype_data = htonl(0x00080000); + /* Set 'mr' field to 1. */ + pdu.subtype_data = htonl(0x00080000); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_MR, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_MR, &val); - assert_int_equal(res, 0); - assert_true(val == 1); + assert_int_equal(res, 0); + assert_true(val == 1); } static void cvf_get_field_tv(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'tv' field to 1. */ - pdu.subtype_data = htonl(0x00010000); + /* Set 'tv' field to 1. */ + pdu.subtype_data = htonl(0x00010000); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_TV, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_TV, &val); - assert_int_equal(res, 0); - assert_true(val == 1); + assert_int_equal(res, 0); + assert_true(val == 1); } static void cvf_get_field_seq_num(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'sequence_num' field to 0x55. */ - pdu.subtype_data = htonl(0x00005500); + /* Set 'sequence_num' field to 0x55. */ + pdu.subtype_data = htonl(0x00005500); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_SEQ_NUM, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_SEQUENCE_NUM, &val); - assert_int_equal(res, 0); - assert_true(val == 0x55); + assert_int_equal(res, 0); + assert_true(val == 0x55); } static void cvf_get_field_tu(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'tu' field to 1. */ - pdu.subtype_data = htonl(0x00000001); + /* Set 'tu' field to 1. */ + pdu.subtype_data = htonl(0x00000001); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_TU, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_TU, &val); - assert_int_equal(res, 0); - assert_true(val == 1); + assert_int_equal(res, 0); + assert_true(val == 1); } static void cvf_get_field_stream_id(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'stream_id' field to 0xAABBCCDDEEFF0001. */ - pdu.stream_id = htobe64(0xAABBCCDDEEFF0001); + /* Set 'stream_id' field to 0xAABBCCDDEEFF0001. */ + pdu.stream_id = htobe64(0xAABBCCDDEEFF0001); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_STREAM_ID, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_STREAM_ID, &val); - assert_int_equal(res, 0); - assert_true(val == 0xAABBCCDDEEFF0001); + assert_int_equal(res, 0); + assert_true(val == 0xAABBCCDDEEFF0001); } static void cvf_get_field_timestamp(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'avtp_timestamp' field to 0x80C0FFEE. */ - pdu.avtp_time = htonl(0x80C0FFEE); + /* Set 'avtp_timestamp' field to 0x80C0FFEE. */ + pdu.avtp_time = htonl(0x80C0FFEE); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_TIMESTAMP, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_AVTP_TIMESTAMP, &val); - assert_int_equal(res, 0); - assert_true(val == 0x80C0FFEE); + assert_int_equal(res, 0); + assert_true(val == 0x80C0FFEE); } static void cvf_get_field_format(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'format' field to AVTP_CVF_FORMAT_RFC. */ - pdu.format_specific = htonl(0x02000000); + /* Set 'format' field to AVTP_CVF_FORMAT_RFC. */ + pdu.format_specific = htonl(0x02000000); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_FORMAT, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_FORMAT, &val); - assert_int_equal(res, 0); - assert_true(val == AVTP_CVF_FORMAT_RFC); + assert_int_equal(res, 0); + assert_true(val == AVTP_CVF_FORMAT_RFC); } static void cvf_get_field_format_subtype(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'format_subtype' field to AVTP_CVF_FORMAT_SUBTYPE_H264. */ - pdu.format_specific = htonl(0x00010000); + /* Set 'format_subtype' field to AVTP_CVF_FORMAT_SUBTYPE_H264. */ + pdu.format_specific = htonl(0x00010000); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_FORMAT_SUBTYPE, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_FORMAT_SUBTYPE, &val); - assert_int_equal(res, 0); - assert_true(val == AVTP_CVF_FORMAT_SUBTYPE_H264); + assert_int_equal(res, 0); + assert_true(val == AVTP_CVF_FORMAT_SUBTYPE_H264); } static void cvf_get_field_data_len(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'stream_data_length' field to 0xAAAA. */ - pdu.packet_info = htonl(0xAAAA0000); + /* Set 'stream_data_length' field to 0xAAAA. */ + pdu.packet_info = htonl(0xAAAA0000); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_STREAM_DATA_LENGTH, &val); - assert_int_equal(res, 0); - assert_true(val == 0xAAAA); + assert_int_equal(res, 0); + assert_true(val == 0xAAAA); } static void cvf_get_field_m(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'M' field to 0x1. */ - pdu.packet_info = htonl(0x00001000); + /* Set 'M' field to 0x1. */ + pdu.packet_info = htonl(0x00001000); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_M, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_M, &val); - assert_int_equal(res, 0); - assert_true(val == 0x1); + assert_int_equal(res, 0); + assert_true(val == 0x1); } static void cvf_get_field_evt(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'evt' field to 0xA. */ - pdu.packet_info = htonl(0x00000A00); + /* Set 'evt' field to 0xA. */ + pdu.packet_info = htonl(0x00000A00); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_EVT, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_EVT, &val); - assert_int_equal(res, 0); - assert_true(val == 0xA); + assert_int_equal(res, 0); + assert_true(val == 0xA); } static void cvf_set_field_null_pdu(void **state) { - int res; + int res; - res = avtp_cvf_pdu_set(NULL, AVTP_CVF_FIELD_SV, 1); + res = avtp_cvf_pdu_set(NULL, AVTP_CVF_FIELD_SV, 1); - assert_int_equal(res, -EINVAL); + assert_int_equal(res, -EINVAL); } static void cvf_set_field_invalid_field(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_MAX, 1); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_MAX, 1); - assert_int_equal(res, -EINVAL); + assert_int_equal(res, -EINVAL); } static void cvf_set_field_sv(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_SV, 1); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_SV, 1); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.subtype_data) == 0x00800000); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.subtype_data) == 0x00800000); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_mr(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_MR, 1); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_MR, 1); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.subtype_data) == 0x00080000); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.subtype_data) == 0x00080000); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_tv(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_TV, 1); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_TV, 1); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.subtype_data) == 0x00010000); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.subtype_data) == 0x00010000); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_seq_num(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_SEQ_NUM, 0x55); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_SEQUENCE_NUM, 0x55); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.subtype_data) == 0x00005500); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.subtype_data) == 0x00005500); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_tu(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_TU, 1); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_TU, 1); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.subtype_data) == 0x00000001); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.subtype_data) == 0x00000001); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_stream_id(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_STREAM_ID, - 0xAABBCCDDEEFF0001); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_STREAM_ID, + 0xAABBCCDDEEFF0001); - assert_int_equal(res, 0); - assert_true(be64toh(pdu.stream_id) == 0xAABBCCDDEEFF0001); - assert_true(pdu.subtype_data == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(be64toh(pdu.stream_id) == 0xAABBCCDDEEFF0001); + assert_true(pdu.subtype_data == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_timestamp(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_TIMESTAMP, 0x80C0FFEE); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_AVTP_TIMESTAMP, 0x80C0FFEE); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.avtp_time) == 0x80C0FFEE); - assert_true(pdu.subtype_data == 0); - assert_true(pdu.stream_id == 0); - assert_true(pdu.format_specific == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.avtp_time) == 0x80C0FFEE); + assert_true(pdu.subtype_data == 0); + assert_true(pdu.stream_id == 0); + assert_true(pdu.format_specific == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_format(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_FORMAT, - AVTP_CVF_FORMAT_RFC); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_FORMAT, + AVTP_CVF_FORMAT_RFC); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.format_specific) == 0x02000000); - assert_true(pdu.subtype_data == 0); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.format_specific) == 0x02000000); + assert_true(pdu.subtype_data == 0); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_format_subtype(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_FORMAT_SUBTYPE, - AVTP_CVF_FORMAT_SUBTYPE_H264); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_FORMAT_SUBTYPE, + AVTP_CVF_FORMAT_SUBTYPE_H264); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.format_specific) == 0x10000); - assert_true(pdu.subtype_data == 0); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.format_specific) == 0x10000); + assert_true(pdu.subtype_data == 0); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_data_len(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, 0xAAAA); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_STREAM_DATA_LENGTH, 0xAAAA); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.packet_info) == 0xAAAA0000); - assert_true(pdu.subtype_data == 0); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.packet_info) == 0xAAAA0000); + assert_true(pdu.subtype_data == 0); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); } static void cvf_set_field_m(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_M, 1); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_M, 1); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.packet_info) == 0x00001000); - assert_true(pdu.subtype_data == 0); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.packet_info) == 0x00001000); + assert_true(pdu.subtype_data == 0); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); } static void cvf_set_field_evt(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_EVT, 0xA); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_EVT, 0xA); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.packet_info) == 0x00000A00); - assert_true(pdu.subtype_data == 0); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.packet_info) == 0x00000A00); + assert_true(pdu.subtype_data == 0); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); } static void cvf_pdu_init_null_pdu(void **state) { - int res; + int res; - res = avtp_cvf_pdu_init(NULL, AVTP_CVF_FORMAT_SUBTYPE_H264); - assert_int_equal(res, -EINVAL); -} - -static void cvf_pdu_init_invalid_subtype(void **state) -{ - int res; - struct avtp_stream_pdu pdu; - - res = avtp_cvf_pdu_init(&pdu, AVTP_CVF_FORMAT_SUBTYPE_JPEG2000 + 1); - assert_int_equal(res, -EINVAL); + res = avtp_cvf_pdu_init(NULL, AVTP_CVF_FORMAT_SUBTYPE_H264); + assert_int_equal(res, -EINVAL); } static void cvf_pdu_init(void **state) { - int res; - struct avtp_stream_pdu pdu; + int res; + struct avtp_stream_pdu pdu; - res = avtp_cvf_pdu_init(&pdu, AVTP_CVF_FORMAT_SUBTYPE_H264); + res = avtp_cvf_pdu_init(&pdu, AVTP_CVF_FORMAT_SUBTYPE_H264); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.subtype_data) == 0x03800000); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(ntohl(pdu.format_specific) == 0x2010000); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.subtype_data) == 0x03800000); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(ntohl(pdu.format_specific) == 0x2010000); + assert_true(pdu.packet_info == 0); } -/**** Tests for H.264 fields ****/ - -static void cvf_get_field_h264_ptv(void **state) +static void cvf_get_field_ptv(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'ptv' field to 1. */ - pdu.packet_info = htonl(0x00002000); + /* Set 'ptv' field to 1. */ + pdu.packet_info = htonl(0x00002000); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_H264_PTV, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_PTV, &val); - assert_int_equal(res, 0); - assert_true(val == 1); + assert_int_equal(res, 0); + assert_true(val == 1); } -static void cvf_get_field_h264_timestamp(void **state) +static void cvf_set_field_ptv(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu *pdu = - alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint32_t)); - struct avtp_cvf_h264_payload *pay = - (struct avtp_cvf_h264_payload *)pdu->avtp_payload; - - /* Set 'h264_timestamp' field (which lives in h264_header) to - * 0x80C0FFEE. */ - pay->h264_header = htonl(0x80C0FFEE); + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_get(pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, &val); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_PTV, 1); - assert_int_equal(res, 0); - assert_true(val == 0x80C0FFEE); + assert_int_equal(res, 0); + assert_true(pdu.subtype_data == 0); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); + assert_true(ntohl(pdu.packet_info) == 0x00002000); } -static void cvf_set_field_h264_ptv(void **state) +/**** Tests for H.264 fields ****/ + +static void cvf_get_field_h264_timestamp(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + Avtp_H264_t pdu; + + /* Set 'h264_timestamp' field (which lives in h264_header) to + * 0x80C0FFEE. */ + uint32_t value = htonl(0x80C0FFEE); + memcpy(&pdu.header, &value, 4); - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_H264_PTV, 1); + res = Avtp_H264_GetField(&pdu, AVTP_H264_FIELD_TIMESTAMP, &val); - assert_int_equal(res, 0); - assert_true(pdu.subtype_data == 0); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); - assert_true(ntohl(pdu.packet_info) == 0x00002000); + assert_int_equal(res, 0); + assert_true(val == 0x80C0FFEE); } static void cvf_set_field_h264_timestamp(void **state) { - int res; - struct avtp_stream_pdu *pdu = - alloca(sizeof(struct avtp_stream_pdu) + sizeof(uint32_t)); - struct avtp_cvf_h264_payload *pay = - (struct avtp_cvf_h264_payload *)pdu->avtp_payload; - memset(pdu, 0, sizeof(struct avtp_stream_pdu) + sizeof(uint32_t)); + int res; + Avtp_H264_t pdu; - res = avtp_cvf_pdu_set(pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, 0x80C0FFEE); + res = Avtp_H264_SetField(&pdu, AVTP_H264_FIELD_TIMESTAMP, 0x80C0FFEE); - assert_int_equal(res, 0); - assert_true(pdu->avtp_time == 0); - assert_true(pdu->subtype_data == 0); - assert_true(pdu->stream_id == 0); - assert_true(pdu->format_specific == 0); - assert_true(pdu->packet_info == 0); - assert_true(ntohl(pay->h264_header) == 0x80C0FFEE); + assert_int_equal(res, 0); + assert_true(ntohl(*(uint32_t*)(&pdu.header)) == 0x80C0FFEE); } int main(void) { - const struct CMUnitTest tests[] = { - cmocka_unit_test(cvf_get_field_null_pdu), - cmocka_unit_test(cvf_get_field_null_val), - cmocka_unit_test(cvf_get_field_invalid_field), - cmocka_unit_test(cvf_get_field_sv), - cmocka_unit_test(cvf_get_field_mr), - cmocka_unit_test(cvf_get_field_tv), - cmocka_unit_test(cvf_get_field_seq_num), - cmocka_unit_test(cvf_get_field_tu), - cmocka_unit_test(cvf_get_field_stream_id), - cmocka_unit_test(cvf_get_field_timestamp), - cmocka_unit_test(cvf_get_field_format), - cmocka_unit_test(cvf_get_field_format_subtype), - cmocka_unit_test(cvf_get_field_data_len), - cmocka_unit_test(cvf_get_field_m), - cmocka_unit_test(cvf_get_field_evt), - cmocka_unit_test(cvf_get_field_h264_ptv), - cmocka_unit_test(cvf_get_field_h264_timestamp), - cmocka_unit_test(cvf_set_field_null_pdu), - cmocka_unit_test(cvf_set_field_invalid_field), - cmocka_unit_test(cvf_set_field_sv), - cmocka_unit_test(cvf_set_field_mr), - cmocka_unit_test(cvf_set_field_tv), - cmocka_unit_test(cvf_set_field_seq_num), - cmocka_unit_test(cvf_set_field_tu), - cmocka_unit_test(cvf_set_field_stream_id), - cmocka_unit_test(cvf_set_field_timestamp), - cmocka_unit_test(cvf_set_field_format), - cmocka_unit_test(cvf_set_field_format_subtype), - cmocka_unit_test(cvf_set_field_data_len), - cmocka_unit_test(cvf_set_field_m), - cmocka_unit_test(cvf_set_field_evt), - cmocka_unit_test(cvf_set_field_h264_ptv), - cmocka_unit_test(cvf_set_field_h264_timestamp), - cmocka_unit_test(cvf_pdu_init_null_pdu), - cmocka_unit_test(cvf_pdu_init_invalid_subtype), - cmocka_unit_test(cvf_pdu_init), - }; - - return cmocka_run_group_tests(tests, NULL, NULL); + const struct CMUnitTest tests[] = { + cmocka_unit_test(cvf_get_field_null_pdu), + cmocka_unit_test(cvf_get_field_null_val), + cmocka_unit_test(cvf_get_field_invalid_field), + cmocka_unit_test(cvf_get_field_sv), + cmocka_unit_test(cvf_get_field_mr), + cmocka_unit_test(cvf_get_field_tv), + cmocka_unit_test(cvf_get_field_seq_num), + cmocka_unit_test(cvf_get_field_tu), + cmocka_unit_test(cvf_get_field_stream_id), + cmocka_unit_test(cvf_get_field_timestamp), + cmocka_unit_test(cvf_get_field_format), + cmocka_unit_test(cvf_get_field_format_subtype), + cmocka_unit_test(cvf_get_field_data_len), + cmocka_unit_test(cvf_get_field_m), + cmocka_unit_test(cvf_get_field_evt), + cmocka_unit_test(cvf_get_field_ptv), + cmocka_unit_test(cvf_get_field_h264_timestamp), + cmocka_unit_test(cvf_set_field_null_pdu), + cmocka_unit_test(cvf_set_field_invalid_field), + cmocka_unit_test(cvf_set_field_sv), + cmocka_unit_test(cvf_set_field_mr), + cmocka_unit_test(cvf_set_field_tv), + cmocka_unit_test(cvf_set_field_seq_num), + cmocka_unit_test(cvf_set_field_tu), + cmocka_unit_test(cvf_set_field_stream_id), + cmocka_unit_test(cvf_set_field_timestamp), + cmocka_unit_test(cvf_set_field_format), + cmocka_unit_test(cvf_set_field_format_subtype), + cmocka_unit_test(cvf_set_field_data_len), + cmocka_unit_test(cvf_set_field_m), + cmocka_unit_test(cvf_set_field_evt), + cmocka_unit_test(cvf_set_field_ptv), + cmocka_unit_test(cvf_set_field_h264_timestamp), + cmocka_unit_test(cvf_pdu_init_null_pdu), + cmocka_unit_test(cvf_pdu_init), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); } From cb5af7ca001c748091e54c0bb304f7a4755457fe Mon Sep 17 00:00:00 2001 From: Adriaan Niess Date: Thu, 27 Jun 2024 18:09:48 +0200 Subject: [PATCH 2/3] Update CVF examples Signed-off-by: Adriaan Niess --- examples/cvf/cvf-listener.c | 2 +- examples/cvf/cvf-talker.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/cvf/cvf-listener.c b/examples/cvf/cvf-listener.c index 37ad835..735a82d 100644 --- a/examples/cvf/cvf-listener.c +++ b/examples/cvf/cvf-listener.c @@ -76,7 +76,7 @@ #include "avtp/cvf/Cvf.h" #include "avtp/cvf/H264.h" #include "avtp/CommonHeader.h" -#include "examples/common.h" +#include "common.h" #define STREAM_ID 0xAABBCCDDEEFF0001 #define DATA_LEN 1400 diff --git a/examples/cvf/cvf-talker.c b/examples/cvf/cvf-talker.c index b86c555..f89141d 100644 --- a/examples/cvf/cvf-talker.c +++ b/examples/cvf/cvf-talker.c @@ -78,7 +78,7 @@ #include "avtp.h" #include "avtp/cvf/Cvf.h" #include "avtp/cvf/H264.h" -#include "examples/common.h" +#include "common.h" #include "avtp/CommonHeader.h" #define STREAM_ID 0xAABBCCDDEEFF0001 @@ -267,7 +267,7 @@ int main(int argc, char *argv[]) argp_parse(&argp, argc, argv, 0, NULL, NULL); - fd = create_talker_socket(priority, 0); + fd = create_talker_socket(priority); if (fd < 0) return 1; From d9745baa9a6b17031280f4bbfa83a2bdab07de79 Mon Sep 17 00:00:00 2001 From: Naresh Nayak Date: Mon, 8 Jul 2024 10:37:35 +0000 Subject: [PATCH 3/3] Replaced tabs with spaces. Signed-off-by: Naresh Nayak --- examples/cvf/cvf-listener.c | 530 +++++++++++++++--------------- examples/cvf/cvf-talker.c | 344 ++++++++++---------- unit/test-cvf.c | 620 ++++++++++++++++++------------------ 3 files changed, 747 insertions(+), 747 deletions(-) diff --git a/examples/cvf/cvf-listener.c b/examples/cvf/cvf-listener.c index 735a82d..ddf2bbb 100644 --- a/examples/cvf/cvf-listener.c +++ b/examples/cvf/cvf-listener.c @@ -85,11 +85,11 @@ #define MAX_PDU_SIZE (AVTP_FULL_HEADER_LEN + DATA_LEN) struct nal_entry { - STAILQ_ENTRY(nal_entry) entries; + STAILQ_ENTRY(nal_entry) entries; - uint16_t len; - struct timespec tspec; - uint8_t nal[DATA_LEN]; + uint16_t len; + struct timespec tspec; + uint8_t nal[DATA_LEN]; }; static STAILQ_HEAD(nal_queue, nal_entry) nals; @@ -98,307 +98,307 @@ static uint8_t macaddr[ETH_ALEN]; static uint8_t expected_seq; static struct argp_option options[] = { - {"dst-addr", 'd', "MACADDR", 0, "Stream Destination MAC address" }, - {"ifname", 'i', "IFNAME", 0, "Network Interface" }, - { 0 } + {"dst-addr", 'd', "MACADDR", 0, "Stream Destination MAC address" }, + {"ifname", 'i', "IFNAME", 0, "Network Interface" }, + { 0 } }; static error_t parser(int key, char *arg, struct argp_state *state) { - int res; - - switch (key) { - case 'd': - res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", - &macaddr[0], &macaddr[1], &macaddr[2], - &macaddr[3], &macaddr[4], &macaddr[5]); - if (res != 6) { - fprintf(stderr, "Invalid address\n"); - exit(EXIT_FAILURE); - } - - break; - case 'i': - strncpy(ifname, arg, sizeof(ifname) - 1); - break; - } - - return 0; + int res; + + switch (key) { + case 'd': + res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &macaddr[0], &macaddr[1], &macaddr[2], + &macaddr[3], &macaddr[4], &macaddr[5]); + if (res != 6) { + fprintf(stderr, "Invalid address\n"); + exit(EXIT_FAILURE); + } + + break; + case 'i': + strncpy(ifname, arg, sizeof(ifname) - 1); + break; + } + + return 0; } static struct argp argp = { options, parser }; static int schedule_nal(int fd, struct timespec *tspec, uint8_t *nal, - ssize_t len) + ssize_t len) { - struct nal_entry *entry; - - entry = malloc(sizeof(*entry)); - if (!entry) { - fprintf(stderr, "Failed to allocate memory\n"); - return -1; - } - - entry->len = len; - entry->tspec.tv_sec = tspec->tv_sec; - entry->tspec.tv_nsec = tspec->tv_nsec; - memcpy(entry->nal, nal, entry->len); - - STAILQ_INSERT_TAIL(&nals, entry, entries); - - /* If this was the first entry inserted onto the queue, we need to arm - * the timer. - */ - if (STAILQ_FIRST(&nals) == entry) { - int res; - - res = arm_timer(fd, tspec); - if (res < 0) { - STAILQ_REMOVE(&nals, entry, nal_entry, entries); - free(entry); - return -1; - } - } - - return 0; + struct nal_entry *entry; + + entry = malloc(sizeof(*entry)); + if (!entry) { + fprintf(stderr, "Failed to allocate memory\n"); + return -1; + } + + entry->len = len; + entry->tspec.tv_sec = tspec->tv_sec; + entry->tspec.tv_nsec = tspec->tv_nsec; + memcpy(entry->nal, nal, entry->len); + + STAILQ_INSERT_TAIL(&nals, entry, entries); + + /* If this was the first entry inserted onto the queue, we need to arm + * the timer. + */ + if (STAILQ_FIRST(&nals) == entry) { + int res; + + res = arm_timer(fd, tspec); + if (res < 0) { + STAILQ_REMOVE(&nals, entry, nal_entry, entries); + free(entry); + return -1; + } + } + + return 0; } static bool is_valid_packet(Avtp_Cvf_t* cvf) { - uint64_t val; - int res; - - res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_SUBTYPE, &val); - if (res < 0) { - fprintf(stderr, "Failed to get subtype field: %d\n", res); - return false; - } - if (val != AVTP_SUBTYPE_CVF) { - fprintf(stderr, "Subtype mismatch: expected %u, got %"PRIu64"\n", AVTP_SUBTYPE_CVF, val); - return false; - } - - res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_VERSION, &val); - if (res < 0) { - fprintf(stderr, "Failed to get version field: %d\n", res); - return false; - } - if (val != 0) { - fprintf(stderr, "Version mismatch: expected %u, got %"PRIu64"\n", 0, val); - return false; - } - - res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_TV, &val); - if (res < 0) { - fprintf(stderr, "Failed to get tv field: %d\n", res); - return false; - } - if (val != 1) { - fprintf(stderr, "tv mismatch: expected %u, got %lu\n", - 1, val); - return false; - } - - res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_STREAM_ID, &val); - if (res < 0) { - fprintf(stderr, "Failed to get stream ID field: %d\n", res); - return false; - } - if (val != STREAM_ID) { - fprintf(stderr, "Stream ID mismatch: expected %lu, got %lu\n", - STREAM_ID, val); - return false; - } - - res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_SEQUENCE_NUM, &val); - if (res < 0) { - fprintf(stderr, "Failed to get sequence num field: %d\n", res); - return false; - } - - if (val != expected_seq) { - /* If we have a sequence number mismatch, we simply log the - * issue and continue to process the packet. We don't want to - * invalidate it since it is a valid packet after all. - */ - fprintf(stderr, - "Sequence number mismatch: expected %u, got %lu\n", - expected_seq, val); - expected_seq = val; - } - - expected_seq++; - - res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_FORMAT, &val); - if (res < 0) { - fprintf(stderr, "Failed to get format field: %d\n", res); - return false; - } - if (val != AVTP_CVF_FORMAT_RFC) { - fprintf(stderr, "Format mismatch: expected %u, got %lu\n", - AVTP_CVF_FORMAT_RFC, val); - return false; - } - - res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_FORMAT_SUBTYPE, &val); - if (res < 0) { - fprintf(stderr, "Failed to get format subtype field: %d\n", - res); - return false; - } - if (val != AVTP_CVF_FORMAT_SUBTYPE_H264) { - fprintf(stderr, "Format mismatch: expected %u, got %lu\n", - AVTP_CVF_FORMAT_SUBTYPE_H264, val); - return false; - } - - return true; + uint64_t val; + int res; + + res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_SUBTYPE, &val); + if (res < 0) { + fprintf(stderr, "Failed to get subtype field: %d\n", res); + return false; + } + if (val != AVTP_SUBTYPE_CVF) { + fprintf(stderr, "Subtype mismatch: expected %u, got %"PRIu64"\n", AVTP_SUBTYPE_CVF, val); + return false; + } + + res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_VERSION, &val); + if (res < 0) { + fprintf(stderr, "Failed to get version field: %d\n", res); + return false; + } + if (val != 0) { + fprintf(stderr, "Version mismatch: expected %u, got %"PRIu64"\n", 0, val); + return false; + } + + res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_TV, &val); + if (res < 0) { + fprintf(stderr, "Failed to get tv field: %d\n", res); + return false; + } + if (val != 1) { + fprintf(stderr, "tv mismatch: expected %u, got %lu\n", + 1, val); + return false; + } + + res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_STREAM_ID, &val); + if (res < 0) { + fprintf(stderr, "Failed to get stream ID field: %d\n", res); + return false; + } + if (val != STREAM_ID) { + fprintf(stderr, "Stream ID mismatch: expected %lu, got %lu\n", + STREAM_ID, val); + return false; + } + + res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_SEQUENCE_NUM, &val); + if (res < 0) { + fprintf(stderr, "Failed to get sequence num field: %d\n", res); + return false; + } + + if (val != expected_seq) { + /* If we have a sequence number mismatch, we simply log the + * issue and continue to process the packet. We don't want to + * invalidate it since it is a valid packet after all. + */ + fprintf(stderr, + "Sequence number mismatch: expected %u, got %lu\n", + expected_seq, val); + expected_seq = val; + } + + expected_seq++; + + res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_FORMAT, &val); + if (res < 0) { + fprintf(stderr, "Failed to get format field: %d\n", res); + return false; + } + if (val != AVTP_CVF_FORMAT_RFC) { + fprintf(stderr, "Format mismatch: expected %u, got %lu\n", + AVTP_CVF_FORMAT_RFC, val); + return false; + } + + res = Avtp_Cvf_GetField(cvf, AVTP_CVF_FIELD_FORMAT_SUBTYPE, &val); + if (res < 0) { + fprintf(stderr, "Failed to get format subtype field: %d\n", + res); + return false; + } + if (val != AVTP_CVF_FORMAT_SUBTYPE_H264) { + fprintf(stderr, "Format mismatch: expected %u, got %lu\n", + AVTP_CVF_FORMAT_SUBTYPE_H264, val); + return false; + } + + return true; } static int get_h264_data_len(Avtp_Cvf_t* cvfHeader, uint16_t *stream_data_len) { - int res; - uint64_t val; + int res; + uint64_t val; - res = Avtp_Cvf_GetField(cvfHeader, AVTP_CVF_FIELD_STREAM_DATA_LENGTH, &val); - if (res < 0) { - fprintf(stderr, "Failed to get data_len field\n"); - return -1; - } - *stream_data_len = val - AVTP_H264_HEADER_LEN; + res = Avtp_Cvf_GetField(cvfHeader, AVTP_CVF_FIELD_STREAM_DATA_LENGTH, &val); + if (res < 0) { + fprintf(stderr, "Failed to get data_len field\n"); + return -1; + } + *stream_data_len = val - AVTP_H264_HEADER_LEN; - return 0; + return 0; } static int new_packet(int sk_fd, int timer_fd) { - int res; - ssize_t n; - uint16_t h264_data_len; - uint64_t avtp_time; - struct timespec tspec; - Avtp_Cvf_t* cvfHeader = alloca(MAX_PDU_SIZE); - Avtp_H264_t* h264Header = (Avtp_H264_t*)(&cvfHeader->payload); - uint8_t* h264Payload = (uint8_t*)(&h264Header->payload); - - memset(cvfHeader, 1, MAX_PDU_SIZE); - - n = recv(sk_fd, cvfHeader, MAX_PDU_SIZE, 0); - if (n < 0 || n > MAX_PDU_SIZE) { - perror("Failed to receive data"); - return -1; - } - - if (!is_valid_packet(cvfHeader)) { - fprintf(stderr, "Dropping packet\n"); - return 0; - } - - res = Avtp_Cvf_GetField(cvfHeader, AVTP_CVF_FIELD_AVTP_TIMESTAMP, &avtp_time); - if (res < 0) { - fprintf(stderr, "Failed to get AVTP time from PDU\n"); - return -1; - } - - res = get_presentation_time(avtp_time, &tspec); - if (res < 0) - return -1; - - res = get_h264_data_len(cvfHeader, &h264_data_len); - if (res < 0) - return -1; - - res = schedule_nal(timer_fd, &tspec, h264Payload, h264_data_len); - if (res < 0) - return -1; - - return 0; + int res; + ssize_t n; + uint16_t h264_data_len; + uint64_t avtp_time; + struct timespec tspec; + Avtp_Cvf_t* cvfHeader = alloca(MAX_PDU_SIZE); + Avtp_H264_t* h264Header = (Avtp_H264_t*)(&cvfHeader->payload); + uint8_t* h264Payload = (uint8_t*)(&h264Header->payload); + + memset(cvfHeader, 1, MAX_PDU_SIZE); + + n = recv(sk_fd, cvfHeader, MAX_PDU_SIZE, 0); + if (n < 0 || n > MAX_PDU_SIZE) { + perror("Failed to receive data"); + return -1; + } + + if (!is_valid_packet(cvfHeader)) { + fprintf(stderr, "Dropping packet\n"); + return 0; + } + + res = Avtp_Cvf_GetField(cvfHeader, AVTP_CVF_FIELD_AVTP_TIMESTAMP, &avtp_time); + if (res < 0) { + fprintf(stderr, "Failed to get AVTP time from PDU\n"); + return -1; + } + + res = get_presentation_time(avtp_time, &tspec); + if (res < 0) + return -1; + + res = get_h264_data_len(cvfHeader, &h264_data_len); + if (res < 0) + return -1; + + res = schedule_nal(timer_fd, &tspec, h264Payload, h264_data_len); + if (res < 0) + return -1; + + return 0; } static int timeout(int fd) { - int res; - ssize_t n; - uint64_t expirations; - struct nal_entry *entry; + int res; + ssize_t n; + uint64_t expirations; + struct nal_entry *entry; - n = read(fd, &expirations, sizeof(uint64_t)); - if (n < 0) { - perror("Failed to read timerfd"); - return -1; - } + n = read(fd, &expirations, sizeof(uint64_t)); + if (n < 0) { + perror("Failed to read timerfd"); + return -1; + } - assert(expirations == 1); + assert(expirations == 1); - entry = STAILQ_FIRST(&nals); - assert(entry != NULL); + entry = STAILQ_FIRST(&nals); + assert(entry != NULL); - res = present_data(entry->nal, entry->len); - if (res < 0) - return -1; + res = present_data(entry->nal, entry->len); + if (res < 0) + return -1; - STAILQ_REMOVE_HEAD(&nals, entries); - free(entry); + STAILQ_REMOVE_HEAD(&nals, entries); + free(entry); - if (!STAILQ_EMPTY(&nals)) { - entry = STAILQ_FIRST(&nals); + if (!STAILQ_EMPTY(&nals)) { + entry = STAILQ_FIRST(&nals); - res = arm_timer(fd, &entry->tspec); - if (res < 0) - return -1; - } + res = arm_timer(fd, &entry->tspec); + if (res < 0) + return -1; + } - return 0; + return 0; } int main(int argc, char *argv[]) { - int sk_fd, timer_fd, res; - struct pollfd fds[2]; - - argp_parse(&argp, argc, argv, 0, NULL, NULL); - - STAILQ_INIT(&nals); - - sk_fd = create_listener_socket(ifname, macaddr, ETH_P_TSN); - if (sk_fd < 0) - return 1; - - timer_fd = timerfd_create(CLOCK_REALTIME, 0); - if (timer_fd < 0) { - close(sk_fd); - return 1; - } - - fds[0].fd = sk_fd; - fds[0].events = POLLIN; - fds[1].fd = timer_fd; - fds[1].events = POLLIN; - - while (1) { - res = poll(fds, 2, -1); - if (res < 0) { - perror("Failed to poll() fds"); - goto err; - } - - if (fds[0].revents & POLLIN) { - res = new_packet(sk_fd, timer_fd); - if (res < 0) - goto err; - } - - if (fds[1].revents & POLLIN) { - res = timeout(timer_fd); - if (res < 0) - goto err; - } - } - - return 0; + int sk_fd, timer_fd, res; + struct pollfd fds[2]; + + argp_parse(&argp, argc, argv, 0, NULL, NULL); + + STAILQ_INIT(&nals); + + sk_fd = create_listener_socket(ifname, macaddr, ETH_P_TSN); + if (sk_fd < 0) + return 1; + + timer_fd = timerfd_create(CLOCK_REALTIME, 0); + if (timer_fd < 0) { + close(sk_fd); + return 1; + } + + fds[0].fd = sk_fd; + fds[0].events = POLLIN; + fds[1].fd = timer_fd; + fds[1].events = POLLIN; + + while (1) { + res = poll(fds, 2, -1); + if (res < 0) { + perror("Failed to poll() fds"); + goto err; + } + + if (fds[0].revents & POLLIN) { + res = new_packet(sk_fd, timer_fd); + if (res < 0) + goto err; + } + + if (fds[1].revents & POLLIN) { + res = timeout(timer_fd); + if (res < 0) + goto err; + } + } + + return 0; err: - close(sk_fd); - close(timer_fd); - return 1; + close(sk_fd); + close(timer_fd); + return 1; } diff --git a/examples/cvf/cvf-talker.c b/examples/cvf/cvf-talker.c index f89141d..5a36d5c 100644 --- a/examples/cvf/cvf-talker.c +++ b/examples/cvf/cvf-talker.c @@ -100,217 +100,217 @@ static uint8_t seq_num; enum process_result {PROCESS_OK, PROCESS_NONE, PROCESS_ERROR}; static struct argp_option options[] = { - {"dst-addr", 'd', "MACADDR", 0, "Stream Destination MAC address" }, - {"ifname", 'i', "IFNAME", 0, "Network Interface" }, - {"max-transit-time", 'm', "MSEC", 0, "Maximum Transit Time in ms" }, - {"prio", 'p', "NUM", 0, "SO_PRIORITY to be set in socket" }, - { 0 } + {"dst-addr", 'd', "MACADDR", 0, "Stream Destination MAC address" }, + {"ifname", 'i', "IFNAME", 0, "Network Interface" }, + {"max-transit-time", 'm', "MSEC", 0, "Maximum Transit Time in ms" }, + {"prio", 'p', "NUM", 0, "SO_PRIORITY to be set in socket" }, + { 0 } }; static error_t parser(int key, char *arg, struct argp_state *state) { - int res; - - switch (key) { - case 'd': - res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", - &macaddr[0], &macaddr[1], &macaddr[2], - &macaddr[3], &macaddr[4], &macaddr[5]); - if (res != 6) { - fprintf(stderr, "Invalid address\n"); - exit(EXIT_FAILURE); - } - - break; - case 'i': - strncpy(ifname, arg, sizeof(ifname) - 1); - break; - case 'm': - max_transit_time = atoi(arg); - break; - case 'p': - priority = atoi(arg); - break; - } - - return 0; + int res; + + switch (key) { + case 'd': + res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &macaddr[0], &macaddr[1], &macaddr[2], + &macaddr[3], &macaddr[4], &macaddr[5]); + if (res != 6) { + fprintf(stderr, "Invalid address\n"); + exit(EXIT_FAILURE); + } + + break; + case 'i': + strncpy(ifname, arg, sizeof(ifname) - 1); + break; + case 'm': + max_transit_time = atoi(arg); + break; + case 'p': + priority = atoi(arg); + break; + } + + return 0; } static struct argp argp = { options, parser }; static int init_pdu(Avtp_Cvf_t* cvf) { - Avtp_Cvf_Init(cvf); - Avtp_Cvf_SetField(cvf, AVTP_CVF_FIELD_FORMAT_SUBTYPE, AVTP_CVF_FORMAT_SUBTYPE_H264); - Avtp_Cvf_SetField(cvf, AVTP_CVF_FIELD_TV, 1); - Avtp_Cvf_SetField(cvf, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID); - Avtp_Cvf_SetField(cvf, AVTP_CVF_FIELD_M, 1); - Avtp_Cvf_SetField(cvf, AVTP_CVF_FIELD_PTV, 0); - - Avtp_H264_t* h264 = (Avtp_H264_t*)(&cvf->payload); - Avtp_H264_Init(h264); - Avtp_H264_SetField(h264, AVTP_H264_FIELD_TIMESTAMP, 0); - - return 0; + Avtp_Cvf_Init(cvf); + Avtp_Cvf_SetField(cvf, AVTP_CVF_FIELD_FORMAT_SUBTYPE, AVTP_CVF_FORMAT_SUBTYPE_H264); + Avtp_Cvf_SetField(cvf, AVTP_CVF_FIELD_TV, 1); + Avtp_Cvf_SetField(cvf, AVTP_CVF_FIELD_STREAM_ID, STREAM_ID); + Avtp_Cvf_SetField(cvf, AVTP_CVF_FIELD_M, 1); + Avtp_Cvf_SetField(cvf, AVTP_CVF_FIELD_PTV, 0); + + Avtp_H264_t* h264 = (Avtp_H264_t*)(&cvf->payload); + Avtp_H264_Init(h264); + Avtp_H264_SetField(h264, AVTP_H264_FIELD_TIMESTAMP, 0); + + return 0; } static ssize_t fill_buffer(void) { - ssize_t n; + ssize_t n; - n = read(STDIN_FILENO, buffer + buffer_level, - sizeof(buffer) - buffer_level); - if (n < 0) { - perror("Could not read from standard input"); - } + n = read(STDIN_FILENO, buffer + buffer_level, + sizeof(buffer) - buffer_level); + if (n < 0) { + perror("Could not read from standard input"); + } - buffer_level += n; + buffer_level += n; - return n; + return n; } static ssize_t start_code_position(size_t offset) { - assert(offset < buffer_level); - - /* Simplified Boyer-Moore, inspired by gstreamer */ - while (offset < buffer_level - 2) { - if (buffer[offset + 2] == 0x1) { - if (buffer[offset] == 0x0 && buffer[offset + 1] == 0x0) - return offset; - offset += 3; - } else if (buffer[offset + 2] == 0x0) { - offset++; - } else { - offset += 3; - } - } - - return -1; + assert(offset < buffer_level); + + /* Simplified Boyer-Moore, inspired by gstreamer */ + while (offset < buffer_level - 2) { + if (buffer[offset + 2] == 0x1) { + if (buffer[offset] == 0x0 && buffer[offset + 1] == 0x0) + return offset; + offset += 3; + } else if (buffer[offset + 2] == 0x0) { + offset++; + } else { + offset += 3; + } + } + + return -1; } static int prepare_packet(Avtp_Cvf_t* cvfHeader, char *nal_data, size_t nal_data_len) { - int res; - uint32_t avtp_time; - Avtp_H264_t* h264Header = (Avtp_H264_t*)(&cvfHeader->payload); - uint8_t* h264Payload = (uint8_t*)(&h264Header->payload); + int res; + uint32_t avtp_time; + Avtp_H264_t* h264Header = (Avtp_H264_t*)(&cvfHeader->payload); + uint8_t* h264Payload = (uint8_t*)(&h264Header->payload); - res = calculate_avtp_time(&avtp_time, max_transit_time); - if (res < 0) { - fprintf(stderr, "Failed to calculate avtp time\n"); - return -1; - } + res = calculate_avtp_time(&avtp_time, max_transit_time); + if (res < 0) { + fprintf(stderr, "Failed to calculate avtp time\n"); + return -1; + } - Avtp_Cvf_SetField(cvfHeader, AVTP_CVF_FIELD_AVTP_TIMESTAMP, avtp_time); - Avtp_Cvf_SetField(cvfHeader, AVTP_CVF_FIELD_SEQUENCE_NUM, seq_num++); - Avtp_Cvf_SetField(cvfHeader, AVTP_CVF_FIELD_STREAM_DATA_LENGTH, nal_data_len + AVTP_H264_HEADER_LEN); + Avtp_Cvf_SetField(cvfHeader, AVTP_CVF_FIELD_AVTP_TIMESTAMP, avtp_time); + Avtp_Cvf_SetField(cvfHeader, AVTP_CVF_FIELD_SEQUENCE_NUM, seq_num++); + Avtp_Cvf_SetField(cvfHeader, AVTP_CVF_FIELD_STREAM_DATA_LENGTH, nal_data_len + AVTP_H264_HEADER_LEN); - memcpy(h264Payload, nal_data, nal_data_len); + memcpy(h264Payload, nal_data, nal_data_len); - return 0; + return 0; } static int process_nal(Avtp_Cvf_t* pdu, bool process_last, - size_t* nal_len) + size_t* nal_len) { - int res; - ssize_t start, end; - - *nal_len = 0; - - start = start_code_position(0); - if (start == -1) { - fprintf(stderr, "Unable to find NAL start\n"); - return PROCESS_NONE; - } - /* Now, let's find where the next starts. This is where current ends */ - end = start_code_position(start + 1); - if (end == -1) { - if (process_last == false) { - return PROCESS_NONE; - } else { - end = buffer_level; - } - } - - *nal_len = end - start; - if (*nal_len > DATA_LEN) { - fprintf(stderr, "NAL length bigger than expected. Expected %u, " - "found %zd\n", DATA_LEN, *nal_len); - goto err; - } - - /* Sets AVTP packet headers and content - the NAL unit */ - res = prepare_packet(pdu, &buffer[start], *nal_len); - if (res < 0) { - goto err; - } - - /* Finally, let's offset any remaining data on the buffer to the - * beginning. Not really efficient, but keep things simple */ - memmove(buffer, buffer + end, buffer_level - end); - buffer_level -= end; - - return PROCESS_OK; + int res; + ssize_t start, end; + + *nal_len = 0; + + start = start_code_position(0); + if (start == -1) { + fprintf(stderr, "Unable to find NAL start\n"); + return PROCESS_NONE; + } + /* Now, let's find where the next starts. This is where current ends */ + end = start_code_position(start + 1); + if (end == -1) { + if (process_last == false) { + return PROCESS_NONE; + } else { + end = buffer_level; + } + } + + *nal_len = end - start; + if (*nal_len > DATA_LEN) { + fprintf(stderr, "NAL length bigger than expected. Expected %u, " + "found %zd\n", DATA_LEN, *nal_len); + goto err; + } + + /* Sets AVTP packet headers and content - the NAL unit */ + res = prepare_packet(pdu, &buffer[start], *nal_len); + if (res < 0) { + goto err; + } + + /* Finally, let's offset any remaining data on the buffer to the + * beginning. Not really efficient, but keep things simple */ + memmove(buffer, buffer + end, buffer_level - end); + buffer_level -= end; + + return PROCESS_OK; err: - return PROCESS_ERROR; + return PROCESS_ERROR; } int main(int argc, char *argv[]) { - int fd, res; - struct sockaddr_ll sk_addr; - uint8_t* pdu = alloca(MAX_PDU_SIZE); - Avtp_Cvf_t* cvf = (Avtp_Cvf_t*)pdu; - - argp_parse(&argp, argc, argv, 0, NULL, NULL); - - fd = create_talker_socket(priority); - if (fd < 0) - return 1; - - res = setup_socket_address(fd, ifname, macaddr, ETH_P_TSN, &sk_addr); - if (res < 0) - goto err; - - res = init_pdu(cvf); - if (res < 0) - goto err; - - while (1) { - ssize_t n; - bool end = false; - - n = fill_buffer(); - if (n == 0) - end = true; - - while (buffer_level > 0) { - enum process_result pr = - process_nal(cvf, end, (size_t *)&n); - if (pr == PROCESS_ERROR) - goto err; - if (pr == PROCESS_NONE) - break; - - n = sendto(fd, pdu, AVTP_FULL_HEADER_LEN + n, 0, - (struct sockaddr *) &sk_addr, sizeof(sk_addr)); - if (n < 0) { - perror("Failed to send data"); - goto err; - } - } - - if (end) - break; - } - - close(fd); - return 0; + int fd, res; + struct sockaddr_ll sk_addr; + uint8_t* pdu = alloca(MAX_PDU_SIZE); + Avtp_Cvf_t* cvf = (Avtp_Cvf_t*)pdu; + + argp_parse(&argp, argc, argv, 0, NULL, NULL); + + fd = create_talker_socket(priority); + if (fd < 0) + return 1; + + res = setup_socket_address(fd, ifname, macaddr, ETH_P_TSN, &sk_addr); + if (res < 0) + goto err; + + res = init_pdu(cvf); + if (res < 0) + goto err; + + while (1) { + ssize_t n; + bool end = false; + + n = fill_buffer(); + if (n == 0) + end = true; + + while (buffer_level > 0) { + enum process_result pr = + process_nal(cvf, end, (size_t *)&n); + if (pr == PROCESS_ERROR) + goto err; + if (pr == PROCESS_NONE) + break; + + n = sendto(fd, pdu, AVTP_FULL_HEADER_LEN + n, 0, + (struct sockaddr *) &sk_addr, sizeof(sk_addr)); + if (n < 0) { + perror("Failed to send data"); + goto err; + } + } + + if (end) + break; + } + + close(fd); + return 0; err: - close(fd); - return 1; + close(fd); + return 1; } diff --git a/unit/test-cvf.c b/unit/test-cvf.c index e7c6af5..76f1025 100644 --- a/unit/test-cvf.c +++ b/unit/test-cvf.c @@ -40,539 +40,539 @@ static void cvf_get_field_null_pdu(void **state) { - int res; - uint64_t val = 1; + int res; + uint64_t val = 1; - res = avtp_cvf_pdu_get(NULL, AVTP_CVF_FIELD_SV, &val); + res = avtp_cvf_pdu_get(NULL, AVTP_CVF_FIELD_SV, &val); - assert_int_equal(res, -EINVAL); + assert_int_equal(res, -EINVAL); } static void cvf_get_field_null_val(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_SV, NULL); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_SV, NULL); - assert_int_equal(res, -EINVAL); + assert_int_equal(res, -EINVAL); } static void cvf_get_field_invalid_field(void **state) { - int res; - uint64_t val = 1; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val = 1; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_MAX, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_MAX, &val); - assert_int_equal(res, -EINVAL); + assert_int_equal(res, -EINVAL); } static void cvf_get_field_sv(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'sv' field to 1. */ - pdu.subtype_data = htonl(0x00800000); + /* Set 'sv' field to 1. */ + pdu.subtype_data = htonl(0x00800000); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_SV, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_SV, &val); - assert_int_equal(res, 0); - assert_true(val == 1); + assert_int_equal(res, 0); + assert_true(val == 1); } static void cvf_get_field_mr(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'mr' field to 1. */ - pdu.subtype_data = htonl(0x00080000); + /* Set 'mr' field to 1. */ + pdu.subtype_data = htonl(0x00080000); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_MR, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_MR, &val); - assert_int_equal(res, 0); - assert_true(val == 1); + assert_int_equal(res, 0); + assert_true(val == 1); } static void cvf_get_field_tv(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'tv' field to 1. */ - pdu.subtype_data = htonl(0x00010000); + /* Set 'tv' field to 1. */ + pdu.subtype_data = htonl(0x00010000); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_TV, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_TV, &val); - assert_int_equal(res, 0); - assert_true(val == 1); + assert_int_equal(res, 0); + assert_true(val == 1); } static void cvf_get_field_seq_num(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'sequence_num' field to 0x55. */ - pdu.subtype_data = htonl(0x00005500); + /* Set 'sequence_num' field to 0x55. */ + pdu.subtype_data = htonl(0x00005500); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_SEQUENCE_NUM, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_SEQUENCE_NUM, &val); - assert_int_equal(res, 0); - assert_true(val == 0x55); + assert_int_equal(res, 0); + assert_true(val == 0x55); } static void cvf_get_field_tu(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'tu' field to 1. */ - pdu.subtype_data = htonl(0x00000001); + /* Set 'tu' field to 1. */ + pdu.subtype_data = htonl(0x00000001); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_TU, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_TU, &val); - assert_int_equal(res, 0); - assert_true(val == 1); + assert_int_equal(res, 0); + assert_true(val == 1); } static void cvf_get_field_stream_id(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'stream_id' field to 0xAABBCCDDEEFF0001. */ - pdu.stream_id = htobe64(0xAABBCCDDEEFF0001); + /* Set 'stream_id' field to 0xAABBCCDDEEFF0001. */ + pdu.stream_id = htobe64(0xAABBCCDDEEFF0001); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_STREAM_ID, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_STREAM_ID, &val); - assert_int_equal(res, 0); - assert_true(val == 0xAABBCCDDEEFF0001); + assert_int_equal(res, 0); + assert_true(val == 0xAABBCCDDEEFF0001); } static void cvf_get_field_timestamp(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'avtp_timestamp' field to 0x80C0FFEE. */ - pdu.avtp_time = htonl(0x80C0FFEE); + /* Set 'avtp_timestamp' field to 0x80C0FFEE. */ + pdu.avtp_time = htonl(0x80C0FFEE); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_AVTP_TIMESTAMP, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_AVTP_TIMESTAMP, &val); - assert_int_equal(res, 0); - assert_true(val == 0x80C0FFEE); + assert_int_equal(res, 0); + assert_true(val == 0x80C0FFEE); } static void cvf_get_field_format(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'format' field to AVTP_CVF_FORMAT_RFC. */ - pdu.format_specific = htonl(0x02000000); + /* Set 'format' field to AVTP_CVF_FORMAT_RFC. */ + pdu.format_specific = htonl(0x02000000); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_FORMAT, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_FORMAT, &val); - assert_int_equal(res, 0); - assert_true(val == AVTP_CVF_FORMAT_RFC); + assert_int_equal(res, 0); + assert_true(val == AVTP_CVF_FORMAT_RFC); } static void cvf_get_field_format_subtype(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'format_subtype' field to AVTP_CVF_FORMAT_SUBTYPE_H264. */ - pdu.format_specific = htonl(0x00010000); + /* Set 'format_subtype' field to AVTP_CVF_FORMAT_SUBTYPE_H264. */ + pdu.format_specific = htonl(0x00010000); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_FORMAT_SUBTYPE, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_FORMAT_SUBTYPE, &val); - assert_int_equal(res, 0); - assert_true(val == AVTP_CVF_FORMAT_SUBTYPE_H264); + assert_int_equal(res, 0); + assert_true(val == AVTP_CVF_FORMAT_SUBTYPE_H264); } static void cvf_get_field_data_len(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'stream_data_length' field to 0xAAAA. */ - pdu.packet_info = htonl(0xAAAA0000); + /* Set 'stream_data_length' field to 0xAAAA. */ + pdu.packet_info = htonl(0xAAAA0000); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_STREAM_DATA_LENGTH, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_STREAM_DATA_LENGTH, &val); - assert_int_equal(res, 0); - assert_true(val == 0xAAAA); + assert_int_equal(res, 0); + assert_true(val == 0xAAAA); } static void cvf_get_field_m(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'M' field to 0x1. */ - pdu.packet_info = htonl(0x00001000); + /* Set 'M' field to 0x1. */ + pdu.packet_info = htonl(0x00001000); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_M, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_M, &val); - assert_int_equal(res, 0); - assert_true(val == 0x1); + assert_int_equal(res, 0); + assert_true(val == 0x1); } static void cvf_get_field_evt(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'evt' field to 0xA. */ - pdu.packet_info = htonl(0x00000A00); + /* Set 'evt' field to 0xA. */ + pdu.packet_info = htonl(0x00000A00); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_EVT, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_EVT, &val); - assert_int_equal(res, 0); - assert_true(val == 0xA); + assert_int_equal(res, 0); + assert_true(val == 0xA); } static void cvf_set_field_null_pdu(void **state) { - int res; + int res; - res = avtp_cvf_pdu_set(NULL, AVTP_CVF_FIELD_SV, 1); + res = avtp_cvf_pdu_set(NULL, AVTP_CVF_FIELD_SV, 1); - assert_int_equal(res, -EINVAL); + assert_int_equal(res, -EINVAL); } static void cvf_set_field_invalid_field(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_MAX, 1); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_MAX, 1); - assert_int_equal(res, -EINVAL); + assert_int_equal(res, -EINVAL); } static void cvf_set_field_sv(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_SV, 1); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_SV, 1); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.subtype_data) == 0x00800000); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.subtype_data) == 0x00800000); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_mr(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_MR, 1); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_MR, 1); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.subtype_data) == 0x00080000); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.subtype_data) == 0x00080000); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_tv(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_TV, 1); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_TV, 1); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.subtype_data) == 0x00010000); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.subtype_data) == 0x00010000); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_seq_num(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_SEQUENCE_NUM, 0x55); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_SEQUENCE_NUM, 0x55); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.subtype_data) == 0x00005500); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.subtype_data) == 0x00005500); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_tu(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_TU, 1); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_TU, 1); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.subtype_data) == 0x00000001); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.subtype_data) == 0x00000001); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_stream_id(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_STREAM_ID, - 0xAABBCCDDEEFF0001); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_STREAM_ID, + 0xAABBCCDDEEFF0001); - assert_int_equal(res, 0); - assert_true(be64toh(pdu.stream_id) == 0xAABBCCDDEEFF0001); - assert_true(pdu.subtype_data == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(be64toh(pdu.stream_id) == 0xAABBCCDDEEFF0001); + assert_true(pdu.subtype_data == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_timestamp(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_AVTP_TIMESTAMP, 0x80C0FFEE); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_AVTP_TIMESTAMP, 0x80C0FFEE); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.avtp_time) == 0x80C0FFEE); - assert_true(pdu.subtype_data == 0); - assert_true(pdu.stream_id == 0); - assert_true(pdu.format_specific == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.avtp_time) == 0x80C0FFEE); + assert_true(pdu.subtype_data == 0); + assert_true(pdu.stream_id == 0); + assert_true(pdu.format_specific == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_format(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_FORMAT, - AVTP_CVF_FORMAT_RFC); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_FORMAT, + AVTP_CVF_FORMAT_RFC); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.format_specific) == 0x02000000); - assert_true(pdu.subtype_data == 0); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.format_specific) == 0x02000000); + assert_true(pdu.subtype_data == 0); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_format_subtype(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_FORMAT_SUBTYPE, - AVTP_CVF_FORMAT_SUBTYPE_H264); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_FORMAT_SUBTYPE, + AVTP_CVF_FORMAT_SUBTYPE_H264); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.format_specific) == 0x10000); - assert_true(pdu.subtype_data == 0); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.format_specific) == 0x10000); + assert_true(pdu.subtype_data == 0); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.packet_info == 0); } static void cvf_set_field_data_len(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_STREAM_DATA_LENGTH, 0xAAAA); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_STREAM_DATA_LENGTH, 0xAAAA); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.packet_info) == 0xAAAA0000); - assert_true(pdu.subtype_data == 0); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.packet_info) == 0xAAAA0000); + assert_true(pdu.subtype_data == 0); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); } static void cvf_set_field_m(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_M, 1); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_M, 1); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.packet_info) == 0x00001000); - assert_true(pdu.subtype_data == 0); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.packet_info) == 0x00001000); + assert_true(pdu.subtype_data == 0); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); } static void cvf_set_field_evt(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_EVT, 0xA); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_EVT, 0xA); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.packet_info) == 0x00000A00); - assert_true(pdu.subtype_data == 0); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.packet_info) == 0x00000A00); + assert_true(pdu.subtype_data == 0); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); } static void cvf_pdu_init_null_pdu(void **state) { - int res; + int res; - res = avtp_cvf_pdu_init(NULL, AVTP_CVF_FORMAT_SUBTYPE_H264); - assert_int_equal(res, -EINVAL); + res = avtp_cvf_pdu_init(NULL, AVTP_CVF_FORMAT_SUBTYPE_H264); + assert_int_equal(res, -EINVAL); } static void cvf_pdu_init(void **state) { - int res; - struct avtp_stream_pdu pdu; + int res; + struct avtp_stream_pdu pdu; - res = avtp_cvf_pdu_init(&pdu, AVTP_CVF_FORMAT_SUBTYPE_H264); + res = avtp_cvf_pdu_init(&pdu, AVTP_CVF_FORMAT_SUBTYPE_H264); - assert_int_equal(res, 0); - assert_true(ntohl(pdu.subtype_data) == 0x03800000); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(ntohl(pdu.format_specific) == 0x2010000); - assert_true(pdu.packet_info == 0); + assert_int_equal(res, 0); + assert_true(ntohl(pdu.subtype_data) == 0x03800000); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(ntohl(pdu.format_specific) == 0x2010000); + assert_true(pdu.packet_info == 0); } static void cvf_get_field_ptv(void **state) { - int res; - uint64_t val; - struct avtp_stream_pdu pdu = { 0 }; + int res; + uint64_t val; + struct avtp_stream_pdu pdu = { 0 }; - /* Set 'ptv' field to 1. */ - pdu.packet_info = htonl(0x00002000); + /* Set 'ptv' field to 1. */ + pdu.packet_info = htonl(0x00002000); - res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_PTV, &val); + res = avtp_cvf_pdu_get(&pdu, AVTP_CVF_FIELD_PTV, &val); - assert_int_equal(res, 0); - assert_true(val == 1); + assert_int_equal(res, 0); + assert_true(val == 1); } static void cvf_set_field_ptv(void **state) { - int res; - struct avtp_stream_pdu pdu = { 0 }; + int res; + struct avtp_stream_pdu pdu = { 0 }; - res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_PTV, 1); + res = avtp_cvf_pdu_set(&pdu, AVTP_CVF_FIELD_PTV, 1); - assert_int_equal(res, 0); - assert_true(pdu.subtype_data == 0); - assert_true(pdu.stream_id == 0); - assert_true(pdu.avtp_time == 0); - assert_true(pdu.format_specific == 0); - assert_true(ntohl(pdu.packet_info) == 0x00002000); + assert_int_equal(res, 0); + assert_true(pdu.subtype_data == 0); + assert_true(pdu.stream_id == 0); + assert_true(pdu.avtp_time == 0); + assert_true(pdu.format_specific == 0); + assert_true(ntohl(pdu.packet_info) == 0x00002000); } /**** Tests for H.264 fields ****/ static void cvf_get_field_h264_timestamp(void **state) { - int res; - uint64_t val; - Avtp_H264_t pdu; + int res; + uint64_t val; + Avtp_H264_t pdu; - /* Set 'h264_timestamp' field (which lives in h264_header) to - * 0x80C0FFEE. */ - uint32_t value = htonl(0x80C0FFEE); - memcpy(&pdu.header, &value, 4); + /* Set 'h264_timestamp' field (which lives in h264_header) to + * 0x80C0FFEE. */ + uint32_t value = htonl(0x80C0FFEE); + memcpy(&pdu.header, &value, 4); - res = Avtp_H264_GetField(&pdu, AVTP_H264_FIELD_TIMESTAMP, &val); + res = Avtp_H264_GetField(&pdu, AVTP_H264_FIELD_TIMESTAMP, &val); - assert_int_equal(res, 0); - assert_true(val == 0x80C0FFEE); + assert_int_equal(res, 0); + assert_true(val == 0x80C0FFEE); } static void cvf_set_field_h264_timestamp(void **state) { - int res; - Avtp_H264_t pdu; + int res; + Avtp_H264_t pdu; - res = Avtp_H264_SetField(&pdu, AVTP_H264_FIELD_TIMESTAMP, 0x80C0FFEE); + res = Avtp_H264_SetField(&pdu, AVTP_H264_FIELD_TIMESTAMP, 0x80C0FFEE); - assert_int_equal(res, 0); - assert_true(ntohl(*(uint32_t*)(&pdu.header)) == 0x80C0FFEE); + assert_int_equal(res, 0); + assert_true(ntohl(*(uint32_t*)(&pdu.header)) == 0x80C0FFEE); } int main(void) { - const struct CMUnitTest tests[] = { - cmocka_unit_test(cvf_get_field_null_pdu), - cmocka_unit_test(cvf_get_field_null_val), - cmocka_unit_test(cvf_get_field_invalid_field), - cmocka_unit_test(cvf_get_field_sv), - cmocka_unit_test(cvf_get_field_mr), - cmocka_unit_test(cvf_get_field_tv), - cmocka_unit_test(cvf_get_field_seq_num), - cmocka_unit_test(cvf_get_field_tu), - cmocka_unit_test(cvf_get_field_stream_id), - cmocka_unit_test(cvf_get_field_timestamp), - cmocka_unit_test(cvf_get_field_format), - cmocka_unit_test(cvf_get_field_format_subtype), - cmocka_unit_test(cvf_get_field_data_len), - cmocka_unit_test(cvf_get_field_m), - cmocka_unit_test(cvf_get_field_evt), - cmocka_unit_test(cvf_get_field_ptv), - cmocka_unit_test(cvf_get_field_h264_timestamp), - cmocka_unit_test(cvf_set_field_null_pdu), - cmocka_unit_test(cvf_set_field_invalid_field), - cmocka_unit_test(cvf_set_field_sv), - cmocka_unit_test(cvf_set_field_mr), - cmocka_unit_test(cvf_set_field_tv), - cmocka_unit_test(cvf_set_field_seq_num), - cmocka_unit_test(cvf_set_field_tu), - cmocka_unit_test(cvf_set_field_stream_id), - cmocka_unit_test(cvf_set_field_timestamp), - cmocka_unit_test(cvf_set_field_format), - cmocka_unit_test(cvf_set_field_format_subtype), - cmocka_unit_test(cvf_set_field_data_len), - cmocka_unit_test(cvf_set_field_m), - cmocka_unit_test(cvf_set_field_evt), - cmocka_unit_test(cvf_set_field_ptv), - cmocka_unit_test(cvf_set_field_h264_timestamp), - cmocka_unit_test(cvf_pdu_init_null_pdu), - cmocka_unit_test(cvf_pdu_init), - }; - - return cmocka_run_group_tests(tests, NULL, NULL); + const struct CMUnitTest tests[] = { + cmocka_unit_test(cvf_get_field_null_pdu), + cmocka_unit_test(cvf_get_field_null_val), + cmocka_unit_test(cvf_get_field_invalid_field), + cmocka_unit_test(cvf_get_field_sv), + cmocka_unit_test(cvf_get_field_mr), + cmocka_unit_test(cvf_get_field_tv), + cmocka_unit_test(cvf_get_field_seq_num), + cmocka_unit_test(cvf_get_field_tu), + cmocka_unit_test(cvf_get_field_stream_id), + cmocka_unit_test(cvf_get_field_timestamp), + cmocka_unit_test(cvf_get_field_format), + cmocka_unit_test(cvf_get_field_format_subtype), + cmocka_unit_test(cvf_get_field_data_len), + cmocka_unit_test(cvf_get_field_m), + cmocka_unit_test(cvf_get_field_evt), + cmocka_unit_test(cvf_get_field_ptv), + cmocka_unit_test(cvf_get_field_h264_timestamp), + cmocka_unit_test(cvf_set_field_null_pdu), + cmocka_unit_test(cvf_set_field_invalid_field), + cmocka_unit_test(cvf_set_field_sv), + cmocka_unit_test(cvf_set_field_mr), + cmocka_unit_test(cvf_set_field_tv), + cmocka_unit_test(cvf_set_field_seq_num), + cmocka_unit_test(cvf_set_field_tu), + cmocka_unit_test(cvf_set_field_stream_id), + cmocka_unit_test(cvf_set_field_timestamp), + cmocka_unit_test(cvf_set_field_format), + cmocka_unit_test(cvf_set_field_format_subtype), + cmocka_unit_test(cvf_set_field_data_len), + cmocka_unit_test(cvf_set_field_m), + cmocka_unit_test(cvf_set_field_evt), + cmocka_unit_test(cvf_set_field_ptv), + cmocka_unit_test(cvf_set_field_h264_timestamp), + cmocka_unit_test(cvf_pdu_init_null_pdu), + cmocka_unit_test(cvf_pdu_init), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); }