diff --git a/CMakeLists.txt b/CMakeLists.txt index fe92dc0..5f08d62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,24 +1,7 @@ -# CMakeLists.txt cmake_minimum_required (VERSION 3.8.2) -project (gpmf-parser) - -set(CMAKE_SUPPRESS_REGENERATION true) -set(CMAKE_CONFIGURATION_TYPES "Debug;Release") - -file(GLOB LIB_SOURCES "GPMF_parser.c" "GPMF_utils.c") -file(GLOB SOURCES ${LIB_SOURCES} "demo/GPMF_demo.c" "demo/GPMF_print.c" "demo/GPMF_mp4reader.c") -add_executable(GPMF_PARSER_BIN ${SOURCES}) -set_target_properties(GPMF_PARSER_BIN PROPERTIES OUTPUT_NAME "${PROJECT_NAME}") -add_library(GPMF_PARSER_LIB ${LIB_SOURCES}) -set_target_properties(GPMF_PARSER_LIB PROPERTIES OUTPUT_NAME "${PROJECT_NAME}") - -set(PC_LINK_FLAGS "-l${PROJECT_NAME}") -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc.in" "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc" @ONLY) +project (gpmf-parser) -install(TARGETS GPMF_PARSER_BIN DESTINATION "bin") -install(TARGETS GPMF_PARSER_LIB DESTINATION "lib") -install(FILES "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc" DESTINATION "lib/pkgconfig") +set(GMPF_PARSER_PUBLIC_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/include) -install(FILES "GPMF_parser.h" "GPMF_common.h" "GPMF_utils.h" DESTINATION "include/gpmf-parser") -install(FILES "demo/GPMF_mp4reader.h" DESTINATION "include/gpmf-parser/demo") +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/src) diff --git a/demo/GPMF_demo.c b/demo/GPMF_demo.c deleted file mode 100644 index 82abb08..0000000 --- a/demo/GPMF_demo.c +++ /dev/null @@ -1,435 +0,0 @@ -/*! @file GPMF_demo.c - * - * @brief Demo to extract GPMF from an MP4 - * - * @version 2.4.0 - * - * (C) Copyright 2017-2020 GoPro Inc (http://gopro.com/). - * - * Licensed under either: - * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 - * - MIT license, http://opensource.org/licenses/MIT - * at your option. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include -#include -#include -#include - -#include "../GPMF_parser.h" -#include "GPMF_mp4reader.h" -#include "../GPMF_utils.h" - -#define SHOW_VIDEO_FRAMERATE 1 -#define SHOW_PAYLOAD_TIME 1 -#define SHOW_ALL_PAYLOADS 0 -#define SHOW_GPMF_STRUCTURE 0 -#define SHOW_PAYLOAD_INDEX 0 -#define SHOW_SCALED_DATA 1 -#define SHOW_THIS_FOUR_CC STR2FOURCC("ACCL") -#define SHOW_COMPUTED_SAMPLERATES 1 - - - -extern void PrintGPMF(GPMF_stream* ms); - -void printHelp(char* name) -{ - printf("usage: %s \n", name); - printf(" -a - %s all payloads\n", SHOW_ALL_PAYLOADS ? "disable" : "show"); - printf(" -g - %s GPMF structure\n", SHOW_GPMF_STRUCTURE ? "disable" : "show"); - printf(" -i - %s index of the payload\n", SHOW_PAYLOAD_INDEX ? "disable" : "show"); - printf(" -s - %s scaled data\n", SHOW_SCALED_DATA ? "disable" : "show"); - printf(" -c - %s computed sample rates\n", SHOW_COMPUTED_SAMPLERATES ? "disable" : "show"); - printf(" -v - %s video framerate\n", SHOW_VIDEO_FRAMERATE ? "disable" : "show"); - printf(" -t - %s time of the payload\n", SHOW_PAYLOAD_TIME ? "disable" : "show"); - printf(" -fWXYZ - show only this fourCC , e.g. -f%c%c%c%c (default) just -f for all\n", PRINTF_4CC(SHOW_THIS_FOUR_CC)); - printf(" -h - this help\n"); - printf(" \n"); - printf(" ver 2.0\n"); -} - -int main(int argc, char* argv[]) -{ - GPMF_ERR ret = GPMF_OK; - GPMF_stream metadata_stream, * ms = &metadata_stream; - double metadatalength; - uint32_t* payload = NULL; - uint32_t payloadsize = 0; - size_t payloadres = 0; - - uint32_t show_all_payloads = SHOW_ALL_PAYLOADS; - uint32_t show_gpmf_structure = SHOW_GPMF_STRUCTURE; - uint32_t show_payload_index = SHOW_PAYLOAD_INDEX; - uint32_t show_scaled_data = SHOW_SCALED_DATA; - uint32_t show_computed_samplerates = SHOW_COMPUTED_SAMPLERATES; - uint32_t show_video_framerate = SHOW_VIDEO_FRAMERATE; - uint32_t show_payload_time = SHOW_PAYLOAD_TIME; - uint32_t show_this_four_cc = SHOW_THIS_FOUR_CC; - - // get file return data - if (argc < 2) - { - printHelp(argv[0]); - return -1; - } - -#if 1 // Search for GPMF Track - size_t mp4handle = OpenMP4Source(argv[1], MOV_GPMF_TRAK_TYPE, MOV_GPMF_TRAK_SUBTYPE, 0); -#else // look for a global GPMF payload in the moov header, within 'udta' - size_t mp4handle = OpenMP4SourceUDTA(argv[1], 0); //Search for GPMF payload with MP4's udta -#endif - if (mp4handle == 0) - { - printf("error: %s is an invalid MP4/MOV or it has no GPMF data\n\n", argv[1]); - - printHelp(argv[0]); - return -1; - } - - for (int i = 2; i < argc; i++) - { - if (argv[i][0] == '-') //feature switches - { - switch (argv[i][1]) - { - case 'a': show_all_payloads ^= 1; break; - case 'g': show_gpmf_structure ^= 1; break; - case 'i': show_payload_index ^= 1; break; - case 's': show_scaled_data ^= 1; break; - case 'c': show_computed_samplerates ^= 1; break; - case 'v': show_video_framerate ^= 1; break; - case 't': show_payload_time ^= 1; break; - case 'f': show_this_four_cc = STR2FOURCC((&(argv[i][2]))); break; - case 'h': printHelp(argv[0]); break; - } - } - } - - - metadatalength = GetDuration(mp4handle); - - if (metadatalength > 0.0) - { - uint32_t index, payloads = GetNumberPayloads(mp4handle); - // printf("found %.2fs of metadata, from %d payloads, within %s\n", metadatalength, payloads, argv[1]); - - uint32_t fr_num, fr_dem; - uint32_t frames = GetVideoFrameRateAndCount(mp4handle, &fr_num, &fr_dem); - if (show_video_framerate) - { - if (frames) - { - printf("VIDEO FRAMERATE:\n %.3f with %d frames\n", (float)fr_num / (float)fr_dem, frames); - } - } - - for (index = 0; index < payloads; index++) - { - double in = 0.0, out = 0.0; //times - payloadsize = GetPayloadSize(mp4handle, index); - payloadres = GetPayloadResource(mp4handle, payloadres, payloadsize); - payload = GetPayload(mp4handle, payloadres, index); - if (payload == NULL) - goto cleanup; - - ret = GetPayloadTime(mp4handle, index, &in, &out); - if (ret != GPMF_OK) - goto cleanup; - - ret = GPMF_Init(ms, payload, payloadsize); - if (ret != GPMF_OK) - goto cleanup; - - if (show_payload_time) - if (show_gpmf_structure || show_payload_index || show_scaled_data) - if (show_all_payloads || index == 0) - printf("PAYLOAD TIME:\n %.3f to %.3f seconds\n", in, out); - - if (show_gpmf_structure) - { - if (show_all_payloads || index == 0) - { - printf("GPMF STRUCTURE:\n"); - // Output (printf) all the contained GPMF data within this payload - ret = GPMF_Validate(ms, GPMF_RECURSE_LEVELS); // optional - if (GPMF_OK != ret) - { - if (GPMF_ERROR_UNKNOWN_TYPE == ret) - { - printf("Unknown GPMF Type within, ignoring\n"); - ret = GPMF_OK; - } - else - printf("Invalid GPMF Structure\n"); - //GPMF_ResetState(ms); - //ret = GPMF_Validate(ms, GPMF_RECURSE_LEVELS); // optional - //goto cleanup; - } - - GPMF_ResetState(ms); - - GPMF_ERR nextret; - do - { - printf(" "); - PrintGPMF(ms); // printf current GPMF KLV - - nextret = GPMF_Next(ms, GPMF_RECURSE_LEVELS | GPMF_TOLERANT); - - while(nextret == GPMF_ERROR_UNKNOWN_TYPE) // or just using GPMF_Next(ms, GPMF_RECURSE_LEVELS|GPMF_TOLERANT) to ignore and skip unknown types - nextret = GPMF_Next(ms, GPMF_RECURSE_LEVELS); - - } while (GPMF_OK == nextret); - GPMF_ResetState(ms); - } - } - - if (show_payload_index) - { - if (show_all_payloads || index == 0) - { - printf("PAYLOAD INDEX:\n"); - ret = GPMF_FindNext(ms, GPMF_KEY_STREAM, GPMF_RECURSE_LEVELS|GPMF_TOLERANT); - while (GPMF_OK == ret) - { - ret = GPMF_SeekToSamples(ms); - if (GPMF_OK == ret) //find the last FOURCC within the stream - { - uint32_t key = GPMF_Key(ms); - GPMF_SampleType type = GPMF_Type(ms); - uint32_t elements = GPMF_ElementsInStruct(ms); - //uint32_t samples = GPMF_Repeat(ms); - uint32_t samples = GPMF_PayloadSampleCount(ms); - - if (samples) - { - printf(" STRM of %c%c%c%c ", PRINTF_4CC(key)); - - if (type == GPMF_TYPE_COMPLEX) - { - GPMF_stream find_stream; - GPMF_CopyState(ms, &find_stream); - - if (GPMF_OK == GPMF_FindPrev(&find_stream, GPMF_KEY_TYPE, GPMF_CURRENT_LEVEL|GPMF_TOLERANT)) - { - char tmp[64]; - char* data = (char*)GPMF_RawData(&find_stream); - uint32_t size = GPMF_RawDataSize(&find_stream); - - if (size < sizeof(tmp)) - { - memcpy(tmp, data, size); - tmp[size] = 0; - printf("of type %s ", tmp); - } - } - - } - else - { - printf("of type %c ", type); - } - - printf("with %d sample%s ", samples, samples > 1 ? "s" : ""); - - if (elements > 1) - printf("-- %d elements per sample", elements); - - printf("\n"); - } - - ret = GPMF_FindNext(ms, GPMF_KEY_STREAM, GPMF_RECURSE_LEVELS|GPMF_TOLERANT); - } - else - { - if (ret != GPMF_OK) // some payload element was corrupt, skip to the next valid GPMF KLV at the previous level. - { - ret = GPMF_Next(ms, GPMF_CURRENT_LEVEL); // this will be the next stream if any more are present. - if (ret != GPMF_OK) - { - break; //skip to the next payload as this one is corrupt - } - } - } - } - GPMF_ResetState(ms); - } - } - - if (show_scaled_data) - { - if (show_all_payloads || index == 0) - { - printf("SCALED DATA:\n"); - while (GPMF_OK == GPMF_FindNext(ms, STR2FOURCC("STRM"), GPMF_RECURSE_LEVELS|GPMF_TOLERANT)) //GoPro Hero5/6/7 Accelerometer) - { - if (GPMF_VALID_FOURCC(show_this_four_cc)) - { - if (GPMF_OK != GPMF_FindNext(ms, show_this_four_cc, GPMF_RECURSE_LEVELS|GPMF_TOLERANT)) - continue; - } - else - { - ret = GPMF_SeekToSamples(ms); - if (GPMF_OK != ret) - continue; - } - - char* rawdata = (char*)GPMF_RawData(ms); - uint32_t key = GPMF_Key(ms); - GPMF_SampleType type = GPMF_Type(ms); - uint32_t samples = GPMF_Repeat(ms); - uint32_t elements = GPMF_ElementsInStruct(ms); - - if (samples) - { - uint32_t buffersize = samples * elements * sizeof(double); - GPMF_stream find_stream; - double* ptr, * tmpbuffer = (double*)malloc(buffersize); - -#define MAX_UNITS 64 -#define MAX_UNITLEN 8 - char units[MAX_UNITS][MAX_UNITLEN] = { "" }; - uint32_t unit_samples = 1; - - char complextype[MAX_UNITS] = { "" }; - uint32_t type_samples = 1; - - if (tmpbuffer) - { - uint32_t i, j; - - //Search for any units to display - GPMF_CopyState(ms, &find_stream); - if (GPMF_OK == GPMF_FindPrev(&find_stream, GPMF_KEY_SI_UNITS, GPMF_CURRENT_LEVEL | GPMF_TOLERANT) || - GPMF_OK == GPMF_FindPrev(&find_stream, GPMF_KEY_UNITS, GPMF_CURRENT_LEVEL | GPMF_TOLERANT)) - { - char* data = (char*)GPMF_RawData(&find_stream); - uint32_t ssize = GPMF_StructSize(&find_stream); - if (ssize > MAX_UNITLEN - 1) ssize = MAX_UNITLEN - 1; - unit_samples = GPMF_Repeat(&find_stream); - - for (i = 0; i < unit_samples && i < MAX_UNITS; i++) - { - memcpy(units[i], data, ssize); - units[i][ssize] = 0; - data += ssize; - } - } - - //Search for TYPE if Complex - GPMF_CopyState(ms, &find_stream); - type_samples = 0; - if (GPMF_OK == GPMF_FindPrev(&find_stream, GPMF_KEY_TYPE, GPMF_CURRENT_LEVEL | GPMF_TOLERANT)) - { - char* data = (char*)GPMF_RawData(&find_stream); - uint32_t ssize = GPMF_StructSize(&find_stream); - if (ssize > MAX_UNITLEN - 1) ssize = MAX_UNITLEN - 1; - type_samples = GPMF_Repeat(&find_stream); - - for (i = 0; i < type_samples && i < MAX_UNITS; i++) - { - complextype[i] = data[i]; - } - } - - //GPMF_FormattedData(ms, tmpbuffer, buffersize, 0, samples); // Output data in LittleEnd, but no scale - if (GPMF_OK == GPMF_ScaledData(ms, tmpbuffer, buffersize, 0, samples, GPMF_TYPE_DOUBLE))//Output scaled data as floats - { - - ptr = tmpbuffer; - int pos = 0; - for (i = 0; i < samples; i++) - { - printf(" %c%c%c%c ", PRINTF_4CC(key)); - - for (j = 0; j < elements; j++) - { - if (type == GPMF_TYPE_STRING_ASCII) - { - printf("%c", rawdata[pos]); - pos++; - ptr++; - } - else if (type_samples == 0) //no TYPE structure - printf("%.3f%s, ", *ptr++, units[j % unit_samples]); - else if (complextype[j] != 'F') - { - printf("%.3f%s, ", *ptr++, units[j % unit_samples]); - pos += GPMF_SizeofType((GPMF_SampleType)complextype[j]); - } - else if (type_samples && complextype[j] == GPMF_TYPE_FOURCC) - { - ptr++; - printf("%c%c%c%c, ", rawdata[pos], rawdata[pos + 1], rawdata[pos + 2], rawdata[pos + 3]); - pos += GPMF_SizeofType((GPMF_SampleType)complextype[j]); - } - } - - - printf("\n"); - } - } - free(tmpbuffer); - } - } - } - GPMF_ResetState(ms); - } - } - } - - - if (show_computed_samplerates) - { - mp4callbacks cbobject; - cbobject.mp4handle = mp4handle; - cbobject.cbGetNumberPayloads = GetNumberPayloads; - cbobject.cbGetPayload = GetPayload; - cbobject.cbGetPayloadSize = GetPayloadSize; - cbobject.cbGetPayloadResource = GetPayloadResource; - cbobject.cbGetPayloadTime = GetPayloadTime; - cbobject.cbFreePayloadResource = FreePayloadResource; - cbobject.cbGetEditListOffsetRationalTime = GetEditListOffsetRationalTime; - - printf("COMPUTED SAMPLERATES:\n"); - // Find all the available Streams and compute they sample rates - while (GPMF_OK == GPMF_FindNext(ms, GPMF_KEY_STREAM, GPMF_RECURSE_LEVELS | GPMF_TOLERANT)) - { - if (GPMF_OK == GPMF_SeekToSamples(ms)) //find the last FOURCC within the stream - { - double start, end; - uint32_t fourcc = GPMF_Key(ms); - - - double rate = GetGPMFSampleRate(cbobject, fourcc, STR2FOURCC("SHUT"), GPMF_SAMPLE_RATE_PRECISE, &start, &end);// GPMF_SAMPLE_RATE_FAST); - printf(" %c%c%c%c sampling rate = %fHz (time %f to %f)\",\n", PRINTF_4CC(fourcc), rate, start, end); - } - } - } - - cleanup: - if (payloadres) FreePayloadResource(mp4handle, payloadres); - if (ms) GPMF_Free(ms); - CloseSource(mp4handle); - } - - if (ret != 0) - { - if (GPMF_ERROR_UNKNOWN_TYPE == ret) - printf("Unknown GPMF Type within\n"); - else - printf("GPMF data has corruption\n"); - } - - return (int)ret; -} diff --git a/demo/GPMF_print.c b/demo/GPMF_print.c deleted file mode 100644 index 996ee56..0000000 --- a/demo/GPMF_print.c +++ /dev/null @@ -1,480 +0,0 @@ -/*! @file GPMF_print.c - * - * @brief Demo to output GPMF for debugging - * - * @version 1.1.0 - * - * (C) Copyright 2017 GoPro Inc (http://gopro.com/). - * - * Licensed under either: - * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 - * - MIT license, http://opensource.org/licenses/MIT - * at your option. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include -#include -#include -#include - -#include "../GPMF_parser.h" - - -#define DBG_MSG printf - - -#define VERBOSE_OUTPUT 0 -#define VERBOSE_LIMIT 6 - -#if VERBOSE_OUTPUT -#define LIMITOUTPUT arraysize = structsize; -#else -#define LIMITOUTPUT if (arraysize > 1 && arraysize*repeat > VERBOSE_LIMIT) repeat = (VERBOSE_LIMIT/arraysize)+1, dots = 1; else if (repeat > VERBOSE_LIMIT) repeat = VERBOSE_LIMIT, dots = 1; -#endif - -void printfData(uint32_t type, uint32_t structsize, uint32_t repeat, void *data) -{ - int dots = 0; - - switch (type) - { - case GPMF_TYPE_STRING_ASCII: - { - char t[256]; - int size = structsize*repeat; - uint32_t arraysize = structsize; - LIMITOUTPUT; - - if (size > 255) - { - size = 255; - } - memcpy(t, (char *)data, size); - t[size] = 0; - - if (arraysize == 1 || repeat == 1) - { - DBG_MSG("\"%s\"", t); - dots = 0; - } - else - { - uint32_t i,j,pos=0; - for (i = 0; i < repeat; i++) - { - DBG_MSG("\""); - for (j = 0; j < arraysize; j++) - { - if (t[pos] != '\0' && t[pos] != ' ') - DBG_MSG("%c", t[pos]); - pos++; - } - DBG_MSG("\", "); - } - } - } - break; - case GPMF_TYPE_SIGNED_BYTE: - { - int8_t *b = (int8_t *)data; - uint32_t arraysize = structsize; - LIMITOUTPUT; - - while (repeat--) - { - arraysize = structsize; - - while (arraysize--) - { - DBG_MSG("%d,", (int8_t)*b); - b++; - } - if (repeat) DBG_MSG(" "); - } - } - break; - case GPMF_TYPE_UNSIGNED_BYTE: - { - uint8_t *b = (uint8_t *)data; - uint32_t arraysize = structsize; - LIMITOUTPUT; - - while (repeat--) - { - arraysize = structsize; - - while (arraysize--) - { - DBG_MSG("%d,", *b); - b++; - } - if (repeat) DBG_MSG(" "); - } - } - break; - case GPMF_TYPE_DOUBLE: - { - uint64_t Swap, *L = (uint64_t *)data; - double *d; - uint32_t arraysize = structsize / sizeof(uint64_t); - LIMITOUTPUT; - - while (repeat--) - { - arraysize = structsize / sizeof(uint64_t); - - while (arraysize--) - { - Swap = BYTESWAP64(*L); - d = (double *)&Swap; - DBG_MSG("%.3f,", *d); - L++; - } - if (repeat) DBG_MSG(" "); - } - } - break; - case GPMF_TYPE_FLOAT: - { - uint32_t Swap, *L = (uint32_t *)data; - float *f; - uint32_t arraysize = structsize / sizeof(uint32_t); - LIMITOUTPUT; - - while (repeat--) - { - arraysize = structsize / sizeof(uint32_t); - - while (arraysize--) - { - Swap = BYTESWAP32(*L); - f = (float *)&Swap; - DBG_MSG("%.3f,", *f); - L++; - } - if (repeat) DBG_MSG(" "); - } - } - break; - case GPMF_TYPE_FOURCC: - { - uint32_t *L = (uint32_t *)data; - uint32_t arraysize = structsize / sizeof(uint32_t); - LIMITOUTPUT; - while (repeat--) - { - arraysize = structsize / sizeof(uint32_t); - - while (arraysize--) - { - DBG_MSG("%c%c%c%c,", PRINTF_4CC(*L)); - L++; - } - if (repeat) DBG_MSG(" "); - } - } - break; - case GPMF_TYPE_GUID: // display GUID in this formatting ABCDEF01-02030405-06070809-10111213 - { - uint8_t *B = (uint8_t *)data; - uint32_t arraysize = structsize; - LIMITOUTPUT; - while (repeat--) - { - arraysize = structsize; - - while (arraysize--) - { - DBG_MSG("%02X", *B); - B++; - } - if (repeat) DBG_MSG(" "); - } - } - break; - case GPMF_TYPE_SIGNED_SHORT: - { - int16_t *s = (int16_t *)data; - uint32_t arraysize = structsize / sizeof(int16_t); - LIMITOUTPUT; - - while (repeat--) - { - arraysize = structsize / sizeof(int16_t); - - while (arraysize--) - { - DBG_MSG("%d,", (int16_t)BYTESWAP16(*s)); - s++; - } - if (repeat) DBG_MSG(" "); - } - } - break; - case GPMF_TYPE_UNSIGNED_SHORT: - { - uint16_t *S = (uint16_t *)data; - uint32_t arraysize = structsize / sizeof(uint16_t); - LIMITOUTPUT; - - while (repeat--) - { - arraysize = structsize / sizeof(uint16_t); - - while (arraysize--) - { - DBG_MSG("%d,", BYTESWAP16(*S)); - S++; - } - if (repeat) DBG_MSG(" "); - } - } - break; - case GPMF_TYPE_SIGNED_LONG: - { - int32_t *l = (int32_t *)data; - uint32_t arraysize = structsize / sizeof(uint32_t); - LIMITOUTPUT; - - while (repeat--) - { - arraysize = structsize / sizeof(uint32_t); - - while (arraysize--) - { - DBG_MSG("%d,", (int32_t)BYTESWAP32(*l)); - l++; - } - if (repeat) DBG_MSG(" "); - } - } - break; - case GPMF_TYPE_UNSIGNED_LONG: - { - uint32_t *L = (uint32_t *)data; - uint32_t arraysize = structsize / sizeof(uint32_t); - LIMITOUTPUT; - while (repeat--) - { - arraysize = structsize / sizeof(uint32_t); - - while (arraysize--) - { - DBG_MSG("%d,", BYTESWAP32(*L)); - L++; - } - if(repeat) DBG_MSG(" "); - } - } - break; - case GPMF_TYPE_Q15_16_FIXED_POINT: - { - int32_t *q = (int32_t *)data; - uint32_t arraysize = structsize / sizeof(int32_t); - LIMITOUTPUT; - - while (repeat--) - { - arraysize = structsize / sizeof(int32_t); - - while (arraysize--) - { - double dq = BYTESWAP32(*q); - dq /= (double)65536.0; - DBG_MSG("%.3f,", dq); - q++; - } - if (repeat) DBG_MSG(" "); - } - } - break; - case GPMF_TYPE_Q31_32_FIXED_POINT: - { - int64_t *Q = (int64_t *)data; - uint32_t arraysize = structsize / sizeof(int64_t); - LIMITOUTPUT; - - while (repeat--) - { - arraysize = structsize / sizeof(int64_t); - - while (arraysize--) - { - uint64_t Q64 = (uint64_t)BYTESWAP64(*Q); - double dq = (double)(Q64 >> (uint64_t)32); - dq += (double)(Q64 & (uint64_t)0xffffffff) / (double)0x100000000; - DBG_MSG("%.3f,", dq); - Q++; - } - if (repeat) DBG_MSG(" "); - } - } - break; - case GPMF_TYPE_UTC_DATE_TIME: - { - char *U = (char *)data; - uint32_t arraysize = structsize / 16; - LIMITOUTPUT; - while (repeat--) - { - arraysize = structsize / 16; - char t[17]; - t[16] = 0; - - while (arraysize--) - { -#ifdef _WINDOWS - strncpy_s(t, 17, U, 16); -#else - strncpy(t, U, 16); -#endif - DBG_MSG("\"%s\",", t); - U += 16; - } - if (repeat) DBG_MSG(" "); - } - } - break; - case GPMF_TYPE_SIGNED_64BIT_INT: - { - int64_t *J = (int64_t *)data; - uint32_t arraysize = structsize / sizeof(int64_t); - LIMITOUTPUT; - while (repeat--) - { - arraysize = structsize / sizeof(int64_t); - - while (arraysize--) - { - DBG_MSG("%lld,", (long long int)BYTESWAP64(*J)); - J++; - } - if (repeat) DBG_MSG(" "); - } - } - break; - case GPMF_TYPE_UNSIGNED_64BIT_INT: - { - uint64_t *J = (uint64_t *)data; - uint32_t arraysize = structsize / sizeof(uint64_t); - LIMITOUTPUT; - while (repeat--) - { - arraysize = structsize / sizeof(uint64_t); - - while (arraysize--) - { - DBG_MSG("%llu,", (long long unsigned int)BYTESWAP64(*J)); - J++; - } - if (repeat) DBG_MSG(" "); - } - } - break; - default: - break; - } - - if (dots) // more data was not output - DBG_MSG("..."); -} - - -void PrintGPMF(GPMF_stream *ms) -{ - if (ms) - { - uint32_t key = GPMF_Key(ms); - uint32_t type = GPMF_Type(ms); - uint32_t structsize = GPMF_StructSize(ms); - uint32_t repeat = GPMF_Repeat(ms); - uint32_t size = GPMF_RawDataSize(ms); - uint32_t indent, level = GPMF_NestLevel(ms); - void *data = GPMF_RawData(ms); - - if (key != GPMF_KEY_DEVICE) level++; - - indent = level; - while (indent > 0 && indent < 10) - { - DBG_MSG(" "); - indent--; - } - if (type == 0) - DBG_MSG("%c%c%c%c nest size %d ", (key >> 0) & 0xff, (key >> 8) & 0xff, (key >> 16) & 0xff, (key >> 24) & 0xff, size); - else if (structsize == 1 || (repeat == 1 && type != '?')) - DBG_MSG("%c%c%c%c type '%c' size %d ", (key >> 0) & 0xff, (key >> 8) & 0xff, (key >> 16) & 0xff, (key >> 24) & 0xff, type == 0 ? '0' : type, size); - else - DBG_MSG("%c%c%c%c type '%c' samplesize %d repeat %d ", (key >> 0) & 0xff, (key >> 8) & 0xff, (key >> 16) & 0xff, (key >> 24) & 0xff, type == 0 ? '0' : type, structsize, repeat); - - if (type && repeat > 0) - { - DBG_MSG("data: "); - - if (type == GPMF_TYPE_COMPLEX) - { - GPMF_stream find_stream; - GPMF_CopyState(ms, &find_stream); - if (GPMF_OK == GPMF_FindPrev(&find_stream, GPMF_KEY_TYPE, GPMF_CURRENT_LEVEL)) - { - char *srctype = (char *)GPMF_RawData(&find_stream); - uint32_t typelen = GPMF_RawDataSize(&find_stream); - int struct_size_of_type; - - struct_size_of_type = GPMF_SizeOfComplexTYPE(srctype, typelen); - if (struct_size_of_type != (int32_t)structsize) - { - DBG_MSG("error: found structure of %d bytes reported as %d bytes", struct_size_of_type, structsize); - } - else - { - char typearray[64]; - uint32_t elements = sizeof(typearray); - uint8_t *bdata = (uint8_t *)data; - uint32_t i; - - if (GPMF_OK == GPMF_ExpandComplexTYPE(srctype, typelen, typearray, &elements)) - { - int dots = 0; - uint32_t arraysize = elements; - - LIMITOUTPUT; - - uint32_t j; - for (j = 0; j < repeat; j++) - { - for (i = 0; i < elements; i++) - { - int elementsize = (int)GPMF_SizeofType((GPMF_SampleType)typearray[i]); - printfData(typearray[i], elementsize, 1, bdata); - bdata += elementsize; - } - if (j < repeat-1) DBG_MSG(" "); - - } - if (dots) - DBG_MSG("..."); - } - } - } - else - { - DBG_MSG("unknown formatting"); - } - } - else - { - printfData(type, structsize, repeat, data); - } - } - - DBG_MSG("\n"); - } -} diff --git a/demo/makefile b/demo/makefile deleted file mode 100644 index 277dc4b..0000000 --- a/demo/makefile +++ /dev/null @@ -1,23 +0,0 @@ -# Address-sanitizer library -ASAN_FLAGS := -lasan -ifneq ($(OS),Windows_NT) - UNAME_S := $(shell uname -s) - ifeq ($(UNAME_S),Darwin) - # macOS requires different a flag - ASAN_FLAGS := -fsanitize=address - endif -endif - -gpmfdemo : GPMF_demo.o GPMF_parser.o GPMF_mp4reader.o GPMF_print.o - gcc -o gpmfdemo GPMF_demo.o GPMF_parser.o GPMF_mp4reader.o GPMF_print.o $(ASAN_FLAGS) - -GPMF_demo.o : GPMF_demo.c ../GPMF_parser.h - gcc -g -c GPMF_demo.c -GPMF_mp4reader.o : GPMF_mp4reader.c ../GPMF_parser.h - gcc -g -c GPMF_mp4reader.c -GPMF_print.o : GPMF_print.c ../GPMF_parser.h - gcc -g -c GPMF_print.c -GPMF_parser.o : ../GPMF_parser.c ../GPMF_parser.h - gcc -g -c ../GPMF_parser.c -clean : - rm gpmfdemo GPMF_demo.o GPMF_parser.o GPMF_mp4reader.o GPMF_print.o \ No newline at end of file diff --git a/GPMF_bitstream.h b/include/gpmf-parser/GPMF_bitstream.h similarity index 96% rename from GPMF_bitstream.h rename to include/gpmf-parser/GPMF_bitstream.h index c71a3b8..9f02722 100644 --- a/GPMF_bitstream.h +++ b/include/gpmf-parser/GPMF_bitstream.h @@ -1,153 +1,153 @@ -/*! @file GPMF_bitstream.h -* -* @brief GPMF Parser library include -* -* Some GPMF streams may contain compressed data, this is useful for high frequency -* sensor data that is highly correlated like IMU data. The compression is Huffman -* coding of the delta between samples, with addition codewords for runs of zeros, -* and optional quantization. The compression scheme is similar to the Huffman coding -* in JPEG. As it intended for lossless compression (with quantize set to 1) it can -* only comrpess/decompress integer based streams. -* -* @version 1.2.0 -* -* (C) Copyright 2017 GoPro Inc (http://gopro.com/). -* -* Licensed under either: -* - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 -* - MIT license, http://opensource.org/licenses/MIT -* at your option. -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -*/ - -#ifndef _GPMF_BITSTREAM_H -#define _GPMF_BITSTREAM_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -typedef struct rlv { // Codebook entries for arbitrary runs - uint16_t size; // Size of code word in bits - uint16_t bits; // Code word bits right justified - uint16_t count; // Run length for zeros - int16_t value; // Value for difference -} RLV; - -typedef const struct { - int length; // Number of entries in the code book - RLV entries[39]; -} RLVTABLE; - -#define BITSTREAM_WORD_TYPE uint16_t // use 16-bit buffer for compression -#define BITSTREAM_WORD_SIZE 16 // use 16-bit buffer for compression -#define BITSTREAM_ERROR_OVERFLOW 1 - -#define BITMASK(n) _bitmask[n] -#define _BITMASK(n) ((((BITSTREAM_WORD_TYPE )1 << (n))) - 1) - -static const BITSTREAM_WORD_TYPE _bitmask[] = -{ - _BITMASK(0), _BITMASK(1), _BITMASK(2), _BITMASK(3), - _BITMASK(4), _BITMASK(5), _BITMASK(6), _BITMASK(7), - _BITMASK(8), _BITMASK(9), _BITMASK(10), _BITMASK(11), - _BITMASK(12), _BITMASK(13), _BITMASK(14), _BITMASK(15), - 0xFFFF -}; - - - -typedef struct bitstream -{ - int32_t error; // Error parsing the bitstream - int32_t bitsFree; // Number of bits available in the current word - uint8_t *lpCurrentWord; // Pointer to next word in block - int32_t wordsUsed; // Number of words used in the block - int32_t dwBlockLength; // Number of entries in the block - uint16_t wBuffer; // Current word bit buffer - uint16_t bits_per_src_word; // Bitused in the source word. e.g. 's' = 16-bits -} BITSTREAM; - - -static RLVTABLE enchuftable = { - 39, - { - { 1, 0b0, 1, 0 }, // m0 - { 2, 0b10, 1, 1 }, // m1 - { 4, 0b1100, 1, 2 }, // m2 - { 5, 0b11011, 1, 3 }, // m3 - { 5, 0b11101, 1, 4 }, // m4 - { 6, 0b110100, 1, 5 }, // m5 - { 6, 0b110101, 1, 6 }, // m6 - { 6, 0b111110, 1, 7 }, // m7 - { 7, 0b1110000, 1, 8 }, // m8 - { 7, 0b1110011, 1, 9 }, // m9 - { 7, 0b1111000, 1, 10 }, // m10 - { 7, 0b1111001, 1, 11 }, // m11 - { 7, 0b1111011, 1, 12 }, // m12 - { 8, 0b11100100, 1, 13 }, // m13 - { 8, 0b11100101, 1, 14 }, // m14 - { 8, 0b11110100, 1, 15 }, // m15 - { 9, 0b111000101, 1, 16 }, // m16 - { 9, 0b111000110, 1, 17 }, // m17 - { 9, 0b111101010, 1, 18 }, // m18 - { 10, 0b1110001000, 1, 19 }, // m19 - { 10, 0b1110001110, 1, 20 }, // m20 - { 10, 0b1111010110, 1, 21 }, // m21 - { 10, 0b1111111100, 1, 22 }, // m22 - { 11, 0b11100010010, 1, 23 }, // m23 - { 11, 0b11100011111, 1, 24 }, // m24 - { 11, 0b11110101110, 1, 25 }, // m25 - { 12, 0b111000100111, 1, 26 }, // m26 - { 12, 0b111000111101, 1, 27 }, // m27 - { 12, 0b111101011111, 1, 28 }, // m28 - { 13, 0b1110001001101, 1, 29 }, // m29 - { 13, 0b1110001111001, 1, 30 }, // m30 - { 13, 0b1111010111101, 1, 31 }, // m31 - { 14, 0b11100010011000, 1, 32 }, // m32 - { 14, 0b11100011110000, 1, 33 }, // m33 - { 14, 0b11110101111000, 1, 34 }, // m34 - { 14, 0b11110101111001, 1, 35 }, // m35 - { 15, 0b111000100110010, 1, 36 }, // m36 - { 15, 0b111000100110011, 1, 37 }, // m37 - { 15, 0b111000111100011, 1, 38 }, // m38 - } -}; - - - -static RLVTABLE enczerorunstable = { - 4, - { - { 7, 0b1111110, 16, 0 }, // z16 - { 8, 0b11111110, 32, 0 }, // z32 - { 9, 0b111111111, 64, 0 }, // z64 - { 10,0b1111111101, 128, 0 }, // z128 - } -}; - -#define HUFF_ESC_CODE_ENTRY 0 -#define HUFF_END_CODE_ENTRY 1 -static RLVTABLE enccontrolcodestable = { - 2, - { - { 16, 0b1110001111000100, 0, 0 }, // escape code for direct data Continue - { 16, 0b1110001111000101, 0, 0 }, // end code. Ends each compressed stream - } -}; - - - -#ifdef __cplusplus -} -#endif - -#endif +/*! @file GPMF_bitstream.h +* +* @brief GPMF Parser library include +* +* Some GPMF streams may contain compressed data, this is useful for high frequency +* sensor data that is highly correlated like IMU data. The compression is Huffman +* coding of the delta between samples, with addition codewords for runs of zeros, +* and optional quantization. The compression scheme is similar to the Huffman coding +* in JPEG. As it intended for lossless compression (with quantize set to 1) it can +* only comrpess/decompress integer based streams. +* +* @version 1.2.0 +* +* (C) Copyright 2017 GoPro Inc (http://gopro.com/). +* +* Licensed under either: +* - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 +* - MIT license, http://opensource.org/licenses/MIT +* at your option. +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +*/ + +#ifndef _GPMF_BITSTREAM_H +#define _GPMF_BITSTREAM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct rlv { // Codebook entries for arbitrary runs + uint16_t size; // Size of code word in bits + uint16_t bits; // Code word bits right justified + uint16_t count; // Run length for zeros + int16_t value; // Value for difference +} RLV; + +typedef const struct { + int length; // Number of entries in the code book + RLV entries[39]; +} RLVTABLE; + +#define BITSTREAM_WORD_TYPE uint16_t // use 16-bit buffer for compression +#define BITSTREAM_WORD_SIZE 16 // use 16-bit buffer for compression +#define BITSTREAM_ERROR_OVERFLOW 1 + +#define BITMASK(n) _bitmask[n] +#define _BITMASK(n) ((((BITSTREAM_WORD_TYPE )1 << (n))) - 1) + +static const BITSTREAM_WORD_TYPE _bitmask[] = +{ + _BITMASK(0), _BITMASK(1), _BITMASK(2), _BITMASK(3), + _BITMASK(4), _BITMASK(5), _BITMASK(6), _BITMASK(7), + _BITMASK(8), _BITMASK(9), _BITMASK(10), _BITMASK(11), + _BITMASK(12), _BITMASK(13), _BITMASK(14), _BITMASK(15), + 0xFFFF +}; + + + +typedef struct bitstream +{ + int32_t error; // Error parsing the bitstream + int32_t bitsFree; // Number of bits available in the current word + uint8_t *lpCurrentWord; // Pointer to next word in block + int32_t wordsUsed; // Number of words used in the block + int32_t dwBlockLength; // Number of entries in the block + uint16_t wBuffer; // Current word bit buffer + uint16_t bits_per_src_word; // Bitused in the source word. e.g. 's' = 16-bits +} BITSTREAM; + + +static RLVTABLE enchuftable = { + 39, + { + { 1, 0b0, 1, 0 }, // m0 + { 2, 0b10, 1, 1 }, // m1 + { 4, 0b1100, 1, 2 }, // m2 + { 5, 0b11011, 1, 3 }, // m3 + { 5, 0b11101, 1, 4 }, // m4 + { 6, 0b110100, 1, 5 }, // m5 + { 6, 0b110101, 1, 6 }, // m6 + { 6, 0b111110, 1, 7 }, // m7 + { 7, 0b1110000, 1, 8 }, // m8 + { 7, 0b1110011, 1, 9 }, // m9 + { 7, 0b1111000, 1, 10 }, // m10 + { 7, 0b1111001, 1, 11 }, // m11 + { 7, 0b1111011, 1, 12 }, // m12 + { 8, 0b11100100, 1, 13 }, // m13 + { 8, 0b11100101, 1, 14 }, // m14 + { 8, 0b11110100, 1, 15 }, // m15 + { 9, 0b111000101, 1, 16 }, // m16 + { 9, 0b111000110, 1, 17 }, // m17 + { 9, 0b111101010, 1, 18 }, // m18 + { 10, 0b1110001000, 1, 19 }, // m19 + { 10, 0b1110001110, 1, 20 }, // m20 + { 10, 0b1111010110, 1, 21 }, // m21 + { 10, 0b1111111100, 1, 22 }, // m22 + { 11, 0b11100010010, 1, 23 }, // m23 + { 11, 0b11100011111, 1, 24 }, // m24 + { 11, 0b11110101110, 1, 25 }, // m25 + { 12, 0b111000100111, 1, 26 }, // m26 + { 12, 0b111000111101, 1, 27 }, // m27 + { 12, 0b111101011111, 1, 28 }, // m28 + { 13, 0b1110001001101, 1, 29 }, // m29 + { 13, 0b1110001111001, 1, 30 }, // m30 + { 13, 0b1111010111101, 1, 31 }, // m31 + { 14, 0b11100010011000, 1, 32 }, // m32 + { 14, 0b11100011110000, 1, 33 }, // m33 + { 14, 0b11110101111000, 1, 34 }, // m34 + { 14, 0b11110101111001, 1, 35 }, // m35 + { 15, 0b111000100110010, 1, 36 }, // m36 + { 15, 0b111000100110011, 1, 37 }, // m37 + { 15, 0b111000111100011, 1, 38 }, // m38 + } +}; + + + +static RLVTABLE enczerorunstable = { + 4, + { + { 7, 0b1111110, 16, 0 }, // z16 + { 8, 0b11111110, 32, 0 }, // z32 + { 9, 0b111111111, 64, 0 }, // z64 + { 10,0b1111111101, 128, 0 }, // z128 + } +}; + +#define HUFF_ESC_CODE_ENTRY 0 +#define HUFF_END_CODE_ENTRY 1 +static RLVTABLE enccontrolcodestable = { + 2, + { + { 16, 0b1110001111000100, 0, 0 }, // escape code for direct data Continue + { 16, 0b1110001111000101, 0, 0 }, // end code. Ends each compressed stream + } +}; + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/GPMF_common.h b/include/gpmf-parser/GPMF_common.h similarity index 98% rename from GPMF_common.h rename to include/gpmf-parser/GPMF_common.h index fa7fee9..4514871 100644 --- a/GPMF_common.h +++ b/include/gpmf-parser/GPMF_common.h @@ -1,140 +1,140 @@ -/*! @file GPMF_common.h - * - * @brief GPMF Parser library include - * - * @version 2.1.0 - * - * (C) Copyright 2017-2020 GoPro Inc (http://gopro.com/). - * - * Licensed under either: - * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 - * - MIT license, http://opensource.org/licenses/MIT - * at your option. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef _GPMF_COMMON_H -#define _GPMF_COMMON_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum GPMF_ERROR -{ - GPMF_OK = 0, - GPMF_ERROR_MEMORY, // NULL Pointer or insufficient memory - GPMF_ERROR_BAD_STRUCTURE, // Non-complaint GPMF structure detected - GPMF_ERROR_BUFFER_END, // reached the end of the provided buffer - GPMF_ERROR_FIND, // Find failed to return the requested data, but structure is valid. - GPMF_ERROR_LAST, // reached the end of a search at the current nest level - GPMF_ERROR_TYPE_NOT_SUPPORTED, // a needed TYPE tuple is missing or has unsupported elements. - GPMF_ERROR_SCALE_NOT_SUPPORTED, // scaling for an non-scaling type, e.g. scaling a FourCC field to a float. - GPMF_ERROR_SCALE_COUNT, // A SCAL tuple has a mismatching element count. - GPMF_ERROR_UNKNOWN_TYPE, // Potentially valid data with a new or unknown type. - GPMF_ERROR_RESERVED // internal usage -} GPMF_ERROR; - -#define GPMF_ERR uint32_t - -typedef enum -{ - GPMF_TYPE_STRING_ASCII = 'c', //single byte 'c' style character string - GPMF_TYPE_SIGNED_BYTE = 'b',//single byte signed number - GPMF_TYPE_UNSIGNED_BYTE = 'B', //single byte unsigned number - GPMF_TYPE_SIGNED_SHORT = 's',//16-bit integer - GPMF_TYPE_UNSIGNED_SHORT = 'S',//16-bit integer - GPMF_TYPE_FLOAT = 'f', //32-bit single precision float (IEEE 754) - GPMF_TYPE_FOURCC = 'F', //32-bit four character tag - GPMF_TYPE_SIGNED_LONG = 'l',//32-bit integer - GPMF_TYPE_UNSIGNED_LONG = 'L', //32-bit integer - GPMF_TYPE_Q15_16_FIXED_POINT = 'q', // Q number Q15.16 - 16-bit signed integer (A) with 16-bit fixed point (B) for A.B value (range -32768.0 to 32767.99998). - GPMF_TYPE_Q31_32_FIXED_POINT = 'Q', // Q number Q31.32 - 32-bit signed integer (A) with 32-bit fixed point (B) for A.B value. - GPMF_TYPE_SIGNED_64BIT_INT = 'j', //64 bit signed long - GPMF_TYPE_UNSIGNED_64BIT_INT = 'J', //64 bit unsigned long - GPMF_TYPE_DOUBLE = 'd', //64 bit double precision float (IEEE 754) - GPMF_TYPE_STRING_UTF8 = 'u', //UTF-8 formatted text string. As the character storage size varies, the size is in bytes, not UTF characters. - GPMF_TYPE_UTC_DATE_TIME = 'U', //128-bit ASCII Date + UTC Time format yymmddhhmmss.sss - 16 bytes ASCII (years 20xx covered) - GPMF_TYPE_GUID = 'G', //128-bit ID (like UUID) - - GPMF_TYPE_COMPLEX = '?', //for sample with complex data structures, base size in bytes. Data is either opaque, or the stream has a TYPE structure field for the sample. - GPMF_TYPE_COMPRESSED = '#', //Huffman compression STRM payloads. 4-CC is compressed as 4-CC '#' - - GPMF_TYPE_NEST = 0, // used to nest more GPMF formatted metadata - - /* ------------- Internal usage only ------------- */ - GPMF_TYPE_EMPTY = 0xfe, // used to distinguish between grouped metadata (like FACE) with no data (no faces detected) and an empty payload (FACE device reported no samples.) - GPMF_TYPE_ERROR = 0xff // used to report an error -} GPMF_SampleType; - - - -#define MAKEID(a,b,c,d) (((d&0xff)<<24)|((c&0xff)<<16)|((b&0xff)<<8)|(a&0xff)) -#define STR2FOURCC(s) ((s[0]<<0)|(s[1]<<8)|(s[2]<<16)|(s[3]<<24)) - -#define BYTESWAP64(a) (((a&0xff)<<56)|((a&0xff00)<<40)|((a&0xff0000)<<24)|((a&0xff000000)<<8) | ((a>>56)&0xff)|((a>>40)&0xff00)|((a>>24)&0xff0000)|((a>>8)&0xff000000) ) -#define BYTESWAP32(a) (((a&0xff)<<24)|((a&0xff00)<<8)|((a>>8)&0xff00)|((a>>24)&0xff)) -#define BYTESWAP16(a) ((((a)>>8)&0xff)|(((a)<<8)&0xff00)) -#define BYTESWAP2x16(a) (((a>>8)&0xff)|((a<<8)&0xff00)|((a>>8)&0xff0000)|((a<<8)&0xff000000)) -#define NOSWAP8(a) (a) - -#define GPMF_SAMPLES(a) (((a>>24) & 0xff)|(((a>>16)&0xff)<<8)) -#define GPMF_SAMPLE_SIZE(a) (((a)>>8)&0xff) -#define GPMF_SAMPLE_TYPE(a) (a&0xff) -#define GPMF_MAKE_TYPE_SIZE_COUNT(t,s,c) ((t)&0xff)|(((s)&0xff)<<8)|(((c)&0xff)<<24)|(((c)&0xff00)<<8) -#define GPMF_DATA_SIZE(a) ((GPMF_SAMPLE_SIZE(a)*GPMF_SAMPLES(a)+3)&~0x3) -#define GPMF_DATA_PACKEDSIZE(a) ((GPMF_SAMPLE_SIZE(a)*GPMF_SAMPLES(a))) -#define GPMF_VALID_FOURCC(a) (((((a>>24)&0xff)>='a'&&((a>>24)&0xff)<='z') || (((a>>24)&0xff)>='A'&&((a>>24)&0xff)<='Z') || (((a>>24)&0xff)>='0'&&((a>>24)&0xff)<='9') || (((a>>24)&0xff)==' ') ) && \ - ( (((a>>16)&0xff)>='a'&&((a>>16)&0xff)<='z') || (((a>>16)&0xff)>='A'&&((a>>16)&0xff)<='Z') || (((a>>16)&0xff)>='0'&&((a>>16)&0xff)<='9') || (((a>>16)&0xff)==' ') ) && \ - ( (((a>>8)&0xff)>='a'&&((a>>8)&0xff)<='z') || (((a>>8)&0xff)>='A'&&((a>>8)&0xff)<='Z') || (((a>>8)&0xff)>='0'&&((a>>8)&0xff)<='9') || (((a>>8)&0xff)==' ') ) && \ - ( (((a>>0)&0xff)>='a'&&((a>>0)&0xff)<='z') || (((a>>0)&0xff)>='A'&&((a>>0)&0xff)<='Z') || (((a>>0)&0xff)>='0'&&((a>>0)&0xff)<='9') || (((a>>0)&0xff)==' ') )) - -#define PRINTF_4CC(k) ((k) >> 0) & 0xff, ((k) >> 8) & 0xff, ((k) >> 16) & 0xff, ((k) >> 24) & 0xff - - -typedef enum GPMFKey // TAG in all caps are GoPro preserved (are defined by GoPro, but can be used by others.) -{ - // Internal Metadata structure and formatting tags - GPMF_KEY_DEVICE = MAKEID('D','E','V','C'),//DEVC - nested device data to speed the parsing of multiple devices in post - GPMF_KEY_DEVICE_ID = MAKEID('D','V','I','D'),//DVID - unique id per stream for a metadata source (in camera or external input) (single 4 byte int) - GPMF_KEY_DEVICE_NAME = MAKEID('D','V','N','M'),//DVNM - human readable device type/name (char string) - GPMF_KEY_STREAM = MAKEID('S','T','R','M'),//STRM - nested channel/stream of telemetry data - GPMF_KEY_STREAM_NAME = MAKEID('S','T','N','M'),//STNM - human readable telemetry/metadata stream type/name (char string) - GPMF_KEY_SI_UNITS = MAKEID('S','I','U','N'),//SIUN - Display string for metadata units where inputs are in SI units "uT","rad/s","km/s","m/s","mm/s" etc. - GPMF_KEY_UNITS = MAKEID('U','N','I','T'),//UNIT - Freedform display string for metadata units (char sting like "RPM", "MPH", "km/h", etc) - GPMF_KEY_MATRIX = MAKEID('M','T','R','X'),//MTRX - 2D matrix for any sensor calibration. - GPMF_KEY_ORIENTATION_IN = MAKEID('O','R','I','N'),//ORIN - input 'n' channel data orientation, lowercase is negative, e.g. "Zxy" or "ABGR". - GPMF_KEY_ORIENTATION_OUT = MAKEID('O','R','I','O'),//ORIO - output 'n' channel data orientation, e.g. "XYZ" or "RGBA". - GPMF_KEY_SCALE = MAKEID('S','C','A','L'),//SCAL - divisor for input data to scale to the correct units. - GPMF_KEY_TYPE = MAKEID('T','Y','P','E'),//TYPE - Type define for complex data structures - GPMF_KEY_TOTAL_SAMPLES = MAKEID('T','S','M','P'),//TOTL - Total Sample Count including the current payload - GPMF_KEY_TICK = MAKEID('T','I','C','K'),//TICK - Beginning of data timing (arrival) in milliseconds. - GPMF_KEY_TOCK = MAKEID('T','O','C','K'),//TOCK - End of data timing (arrival) in milliseconds. - GPMF_KEY_TIME_OFFSET = MAKEID('T','I','M','O'),//TIMO - Time offset of the metadata stream that follows (single 4 byte float) - GPMF_KEY_TIMING_OFFSET = MAKEID('T','I','M','O'),//TIMO - duplicated, as older code might use the other version of TIMO - GPMF_KEY_TIME_STAMP = MAKEID('S','T','M','P'),//STMP - Time stamp for the first sample. - GPMF_KEY_TIME_STAMPS = MAKEID('S','T','P','S'),//STPS - Stream of all the timestamps delivered (Generally don't use this. This would be if your sensor has no peroidic times, yet precision is required, or for debugging.) - GPMF_KEY_PREFORMATTED = MAKEID('P','F','R','M'),//PFRM - GPMF data - GPMF_KEY_TEMPERATURE_C = MAKEID('T','M','P','C'),//TMPC - Temperature in Celsius - GPMF_KEY_EMPTY_PAYLOADS = MAKEID('E','M','P','T'),//EMPT - Payloads that are empty since the device start (e.g. BLE disconnect.) - GPMF_KEY_QUANTIZE = MAKEID('Q','U','A','N'),//QUAN - quantize used to enable stream compression - 1 - enable, 2+ enable and quantize by this value - GPMF_KEY_VERSION = MAKEID('V','E','R','S'),//VERS - version of the metadata stream (debugging) - GPMF_KEY_FREESPACE = MAKEID('F','R','E','E'),//FREE - n bytes reserved for more metadata added to an existing stream - GPMF_KEY_REMARK = MAKEID('R','M','R','K'),//RMRK - adding comments to the bitstream (debugging) - - GPMF_KEY_END = 0//(null) -} GPMFKey; - - - -#ifdef __cplusplus -} -#endif - -#endif +/*! @file GPMF_common.h + * + * @brief GPMF Parser library include + * + * @version 2.1.0 + * + * (C) Copyright 2017-2020 GoPro Inc (http://gopro.com/). + * + * Licensed under either: + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - MIT license, http://opensource.org/licenses/MIT + * at your option. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _GPMF_COMMON_H +#define _GPMF_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum GPMF_ERROR +{ + GPMF_OK = 0, + GPMF_ERROR_MEMORY, // NULL Pointer or insufficient memory + GPMF_ERROR_BAD_STRUCTURE, // Non-complaint GPMF structure detected + GPMF_ERROR_BUFFER_END, // reached the end of the provided buffer + GPMF_ERROR_FIND, // Find failed to return the requested data, but structure is valid. + GPMF_ERROR_LAST, // reached the end of a search at the current nest level + GPMF_ERROR_TYPE_NOT_SUPPORTED, // a needed TYPE tuple is missing or has unsupported elements. + GPMF_ERROR_SCALE_NOT_SUPPORTED, // scaling for an non-scaling type, e.g. scaling a FourCC field to a float. + GPMF_ERROR_SCALE_COUNT, // A SCAL tuple has a mismatching element count. + GPMF_ERROR_UNKNOWN_TYPE, // Potentially valid data with a new or unknown type. + GPMF_ERROR_RESERVED // internal usage +} GPMF_ERROR; + +#define GPMF_ERR uint32_t + +typedef enum +{ + GPMF_TYPE_STRING_ASCII = 'c', //single byte 'c' style character string + GPMF_TYPE_SIGNED_BYTE = 'b',//single byte signed number + GPMF_TYPE_UNSIGNED_BYTE = 'B', //single byte unsigned number + GPMF_TYPE_SIGNED_SHORT = 's',//16-bit integer + GPMF_TYPE_UNSIGNED_SHORT = 'S',//16-bit integer + GPMF_TYPE_FLOAT = 'f', //32-bit single precision float (IEEE 754) + GPMF_TYPE_FOURCC = 'F', //32-bit four character tag + GPMF_TYPE_SIGNED_LONG = 'l',//32-bit integer + GPMF_TYPE_UNSIGNED_LONG = 'L', //32-bit integer + GPMF_TYPE_Q15_16_FIXED_POINT = 'q', // Q number Q15.16 - 16-bit signed integer (A) with 16-bit fixed point (B) for A.B value (range -32768.0 to 32767.99998). + GPMF_TYPE_Q31_32_FIXED_POINT = 'Q', // Q number Q31.32 - 32-bit signed integer (A) with 32-bit fixed point (B) for A.B value. + GPMF_TYPE_SIGNED_64BIT_INT = 'j', //64 bit signed long + GPMF_TYPE_UNSIGNED_64BIT_INT = 'J', //64 bit unsigned long + GPMF_TYPE_DOUBLE = 'd', //64 bit double precision float (IEEE 754) + GPMF_TYPE_STRING_UTF8 = 'u', //UTF-8 formatted text string. As the character storage size varies, the size is in bytes, not UTF characters. + GPMF_TYPE_UTC_DATE_TIME = 'U', //128-bit ASCII Date + UTC Time format yymmddhhmmss.sss - 16 bytes ASCII (years 20xx covered) + GPMF_TYPE_GUID = 'G', //128-bit ID (like UUID) + + GPMF_TYPE_COMPLEX = '?', //for sample with complex data structures, base size in bytes. Data is either opaque, or the stream has a TYPE structure field for the sample. + GPMF_TYPE_COMPRESSED = '#', //Huffman compression STRM payloads. 4-CC is compressed as 4-CC '#' + + GPMF_TYPE_NEST = 0, // used to nest more GPMF formatted metadata + + /* ------------- Internal usage only ------------- */ + GPMF_TYPE_EMPTY = 0xfe, // used to distinguish between grouped metadata (like FACE) with no data (no faces detected) and an empty payload (FACE device reported no samples.) + GPMF_TYPE_ERROR = 0xff // used to report an error +} GPMF_SampleType; + + + +#define MAKEID(a,b,c,d) (((d&0xff)<<24)|((c&0xff)<<16)|((b&0xff)<<8)|(a&0xff)) +#define STR2FOURCC(s) ((s[0]<<0)|(s[1]<<8)|(s[2]<<16)|(s[3]<<24)) + +#define BYTESWAP64(a) (((a&0xff)<<56)|((a&0xff00)<<40)|((a&0xff0000)<<24)|((a&0xff000000)<<8) | ((a>>56)&0xff)|((a>>40)&0xff00)|((a>>24)&0xff0000)|((a>>8)&0xff000000) ) +#define BYTESWAP32(a) (((a&0xff)<<24)|((a&0xff00)<<8)|((a>>8)&0xff00)|((a>>24)&0xff)) +#define BYTESWAP16(a) ((((a)>>8)&0xff)|(((a)<<8)&0xff00)) +#define BYTESWAP2x16(a) (((a>>8)&0xff)|((a<<8)&0xff00)|((a>>8)&0xff0000)|((a<<8)&0xff000000)) +#define NOSWAP8(a) (a) + +#define GPMF_SAMPLES(a) (((a>>24) & 0xff)|(((a>>16)&0xff)<<8)) +#define GPMF_SAMPLE_SIZE(a) (((a)>>8)&0xff) +#define GPMF_SAMPLE_TYPE(a) (a&0xff) +#define GPMF_MAKE_TYPE_SIZE_COUNT(t,s,c) ((t)&0xff)|(((s)&0xff)<<8)|(((c)&0xff)<<24)|(((c)&0xff00)<<8) +#define GPMF_DATA_SIZE(a) ((GPMF_SAMPLE_SIZE(a)*GPMF_SAMPLES(a)+3)&~0x3) +#define GPMF_DATA_PACKEDSIZE(a) ((GPMF_SAMPLE_SIZE(a)*GPMF_SAMPLES(a))) +#define GPMF_VALID_FOURCC(a) (((((a>>24)&0xff)>='a'&&((a>>24)&0xff)<='z') || (((a>>24)&0xff)>='A'&&((a>>24)&0xff)<='Z') || (((a>>24)&0xff)>='0'&&((a>>24)&0xff)<='9') || (((a>>24)&0xff)==' ') ) && \ + ( (((a>>16)&0xff)>='a'&&((a>>16)&0xff)<='z') || (((a>>16)&0xff)>='A'&&((a>>16)&0xff)<='Z') || (((a>>16)&0xff)>='0'&&((a>>16)&0xff)<='9') || (((a>>16)&0xff)==' ') ) && \ + ( (((a>>8)&0xff)>='a'&&((a>>8)&0xff)<='z') || (((a>>8)&0xff)>='A'&&((a>>8)&0xff)<='Z') || (((a>>8)&0xff)>='0'&&((a>>8)&0xff)<='9') || (((a>>8)&0xff)==' ') ) && \ + ( (((a>>0)&0xff)>='a'&&((a>>0)&0xff)<='z') || (((a>>0)&0xff)>='A'&&((a>>0)&0xff)<='Z') || (((a>>0)&0xff)>='0'&&((a>>0)&0xff)<='9') || (((a>>0)&0xff)==' ') )) + +#define PRINTF_4CC(k) ((k) >> 0) & 0xff, ((k) >> 8) & 0xff, ((k) >> 16) & 0xff, ((k) >> 24) & 0xff + + +typedef enum GPMFKey // TAG in all caps are GoPro preserved (are defined by GoPro, but can be used by others.) +{ + // Internal Metadata structure and formatting tags + GPMF_KEY_DEVICE = MAKEID('D','E','V','C'),//DEVC - nested device data to speed the parsing of multiple devices in post + GPMF_KEY_DEVICE_ID = MAKEID('D','V','I','D'),//DVID - unique id per stream for a metadata source (in camera or external input) (single 4 byte int) + GPMF_KEY_DEVICE_NAME = MAKEID('D','V','N','M'),//DVNM - human readable device type/name (char string) + GPMF_KEY_STREAM = MAKEID('S','T','R','M'),//STRM - nested channel/stream of telemetry data + GPMF_KEY_STREAM_NAME = MAKEID('S','T','N','M'),//STNM - human readable telemetry/metadata stream type/name (char string) + GPMF_KEY_SI_UNITS = MAKEID('S','I','U','N'),//SIUN - Display string for metadata units where inputs are in SI units "uT","rad/s","km/s","m/s","mm/s" etc. + GPMF_KEY_UNITS = MAKEID('U','N','I','T'),//UNIT - Freedform display string for metadata units (char sting like "RPM", "MPH", "km/h", etc) + GPMF_KEY_MATRIX = MAKEID('M','T','R','X'),//MTRX - 2D matrix for any sensor calibration. + GPMF_KEY_ORIENTATION_IN = MAKEID('O','R','I','N'),//ORIN - input 'n' channel data orientation, lowercase is negative, e.g. "Zxy" or "ABGR". + GPMF_KEY_ORIENTATION_OUT = MAKEID('O','R','I','O'),//ORIO - output 'n' channel data orientation, e.g. "XYZ" or "RGBA". + GPMF_KEY_SCALE = MAKEID('S','C','A','L'),//SCAL - divisor for input data to scale to the correct units. + GPMF_KEY_TYPE = MAKEID('T','Y','P','E'),//TYPE - Type define for complex data structures + GPMF_KEY_TOTAL_SAMPLES = MAKEID('T','S','M','P'),//TOTL - Total Sample Count including the current payload + GPMF_KEY_TICK = MAKEID('T','I','C','K'),//TICK - Beginning of data timing (arrival) in milliseconds. + GPMF_KEY_TOCK = MAKEID('T','O','C','K'),//TOCK - End of data timing (arrival) in milliseconds. + GPMF_KEY_TIME_OFFSET = MAKEID('T','I','M','O'),//TIMO - Time offset of the metadata stream that follows (single 4 byte float) + GPMF_KEY_TIMING_OFFSET = MAKEID('T','I','M','O'),//TIMO - duplicated, as older code might use the other version of TIMO + GPMF_KEY_TIME_STAMP = MAKEID('S','T','M','P'),//STMP - Time stamp for the first sample. + GPMF_KEY_TIME_STAMPS = MAKEID('S','T','P','S'),//STPS - Stream of all the timestamps delivered (Generally don't use this. This would be if your sensor has no peroidic times, yet precision is required, or for debugging.) + GPMF_KEY_PREFORMATTED = MAKEID('P','F','R','M'),//PFRM - GPMF data + GPMF_KEY_TEMPERATURE_C = MAKEID('T','M','P','C'),//TMPC - Temperature in Celsius + GPMF_KEY_EMPTY_PAYLOADS = MAKEID('E','M','P','T'),//EMPT - Payloads that are empty since the device start (e.g. BLE disconnect.) + GPMF_KEY_QUANTIZE = MAKEID('Q','U','A','N'),//QUAN - quantize used to enable stream compression - 1 - enable, 2+ enable and quantize by this value + GPMF_KEY_VERSION = MAKEID('V','E','R','S'),//VERS - version of the metadata stream (debugging) + GPMF_KEY_FREESPACE = MAKEID('F','R','E','E'),//FREE - n bytes reserved for more metadata added to an existing stream + GPMF_KEY_REMARK = MAKEID('R','M','R','K'),//RMRK - adding comments to the bitstream (debugging) + + GPMF_KEY_END = 0//(null) +} GPMFKey; + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/demo/GPMF_mp4reader.h b/include/gpmf-parser/GPMF_mp4reader.h similarity index 100% rename from demo/GPMF_mp4reader.h rename to include/gpmf-parser/GPMF_mp4reader.h diff --git a/GPMF_parser.h b/include/gpmf-parser/GPMF_parser.h similarity index 94% rename from GPMF_parser.h rename to include/gpmf-parser/GPMF_parser.h index 2d9ea31..b1c9ac2 100644 --- a/GPMF_parser.h +++ b/include/gpmf-parser/GPMF_parser.h @@ -1,13 +1,13 @@ /*! @file GPMF_parser.h - * + * * @brief GPMF Parser library include - * + * * @version 2.0.0 - * + * * (C) Copyright 2017-2020 GoPro Inc (http://gopro.com/). * * Licensed under either: - * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 * - MIT license, http://opensource.org/licenses/MIT * at your option. * @@ -16,15 +16,15 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * + * */ #ifndef _GPMF_PARSER_H #define _GPMF_PARSER_H -#include -#include #include "GPMF_common.h" +#include +#include #ifdef __cplusplus extern "C" { @@ -53,18 +53,18 @@ typedef enum GPMF_LEVELS { GPMF_CURRENT_LEVEL = 0, // search or validate within the current GPMF next level GPMF_RECURSE_LEVELS = 1, // search or validate recursing all levels - GPMF_TOLERANT = 2 // Ignore minor errors like unknown datatypes if the structure is otherwise valid. + GPMF_TOLERANT = 2 // Ignore minor errors like unknown datatypes if the structure is otherwise valid. } GPMF_LEVELS; - -// Prepare GPMF data + +// Prepare GPMF data GPMF_ERR GPMF_Init(GPMF_stream *gs, uint32_t *buffer, uint32_t datasize); //Initialize a GPMF_stream for parsing a particular buffer. GPMF_ERR GPMF_ResetState(GPMF_stream *gs); //Read from beginning of the buffer again -GPMF_ERR GPMF_CopyState(GPMF_stream *src, GPMF_stream *dst); //Copy state, -GPMF_ERR GPMF_Validate(GPMF_stream *gs, GPMF_LEVELS recurse); //Is the nest structure valid GPMF? +GPMF_ERR GPMF_CopyState(GPMF_stream *src, GPMF_stream *dst); //Copy state, +GPMF_ERR GPMF_Validate(GPMF_stream *gs, GPMF_LEVELS recurse); //Is the nest structure valid GPMF? -// Navigate through GPMF data +// Navigate through GPMF data GPMF_ERR GPMF_Next(GPMF_stream *gs, GPMF_LEVELS recurse); //Step to the next GPMF KLV entrance, optionally recurse up or down nesting levels. GPMF_ERR GPMF_FindPrev(GPMF_stream *gs, uint32_t fourCC, GPMF_LEVELS recurse); //find a previous FourCC -- at the current level only if recurse is false GPMF_ERR GPMF_FindNext(GPMF_stream *gs, uint32_t fourCC, GPMF_LEVELS recurse); //find a particular FourCC upcoming -- at the current level only if recurse is false @@ -77,7 +77,7 @@ uint32_t GPMF_StructSize(GPMF_stream *gs); //return the current sam uint32_t GPMF_Repeat(GPMF_stream *gs); //return the current repeat or the number of samples of this structure uint32_t GPMF_PayloadSampleCount(GPMF_stream *gs); //return the current number of samples of this structure, supporting multisample entries. uint32_t GPMF_ElementsInStruct(GPMF_stream *gs); //return the current number elements within the structure (e.g. 3-axis gyro) -uint32_t GPMF_RawDataSize(GPMF_stream *gs); //return the data size for the current GPMF KLV +uint32_t GPMF_RawDataSize(GPMF_stream *gs); //return the data size for the current GPMF KLV void * GPMF_RawData(GPMF_stream *gs); //return a pointer the KLV data (which is Bigendian if the type is known.) @@ -92,10 +92,10 @@ GPMF_ERR GPMF_DeviceName(GPMF_stream *gs, char *devicename_buf, uint32_t devicen // Utilities for data types uint32_t GPMF_SizeofType(GPMF_SampleType type); // GPMF equivalent to sizeof(type) uint32_t GPMF_ExpandComplexTYPE(char *src, uint32_t srcsize, char *dst, uint32_t *dstsize); // GPMF using TYPE for cmple structure. { float val[16],uin32_t flags; } has type "f[8]L", this tools expands to the simpler format "ffffffffL" -uint32_t GPMF_SizeOfComplexTYPE(char *typearray, uint32_t typestringlength); // GPMF equivalent to sizeof(typedef) for complex types. +uint32_t GPMF_SizeOfComplexTYPE(char *typearray, uint32_t typestringlength); // GPMF equivalent to sizeof(typedef) for complex types. GPMF_ERR GPMF_Reserved(uint32_t key); // Test for a reverse GPMF Key, returns GPMF_OK is not reversed. -//Tools for extracting sensor data +//Tools for extracting sensor data uint32_t GPMF_FormattedDataSize(GPMF_stream *gs); //return the decompressed data size for the current GPMF KLV uint32_t GPMF_ScaledDataSize(GPMF_stream *gs, GPMF_SampleType type); //return the decompressed data size for the current GPMF KLV GPMF_ERR GPMF_FormattedData(GPMF_stream *gs, void *buffer, uint32_t buffersize, uint32_t sample_offset, uint32_t read_samples); // extract 'n' samples into local endian memory format. @@ -107,7 +107,7 @@ typedef struct GPMF_codebook { int16_t value; //value to store uint8_t offset; //0 to 128+ bytes to skip before store (leading zeros) - uint8_t bits_used; //1 to 16,32 (if escape code > 16 then read from bit-steam), + uint8_t bits_used; //1 to 16,32 (if escape code > 16 then read from bit-steam), int8_t bytes_stored; //bytes stored in value: 0, 1 or 2 int8_t command; //0 - OKAY, -1 valid code, 1 - end } GPMF_codebook; @@ -117,7 +117,7 @@ GPMF_ERR GPMF_AllocCodebook(size_t *cbhandle); GPMF_ERR GPMF_FreeCodebook(size_t cbhandle); GPMF_ERR GPMF_DecompressedSize(GPMF_stream *gs, uint32_t *neededsize); GPMF_ERR GPMF_Decompress(GPMF_stream *gs, uint32_t *localbuf, uint32_t localbuf_size); -GPMF_ERR GPMF_Free(GPMF_stream* gs); +GPMF_ERR GPMF_Free(GPMF_stream* gs); #ifdef __cplusplus diff --git a/GPMF_utils.h b/include/gpmf-parser/GPMF_utils.h similarity index 100% rename from GPMF_utils.h rename to include/gpmf-parser/GPMF_utils.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..d03db5a --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,12 @@ +add_library(gpmf-parser STATIC + ${CMAKE_CURRENT_LIST_DIR}/GPMF_mp4reader.c + ${CMAKE_CURRENT_LIST_DIR}/GPMF_parser.c + ${CMAKE_CURRENT_LIST_DIR}/GPMF_utils.c +) + +target_include_directories(gpmf-parser + PRIVATE + ${GMPF_PARSER_PUBLIC_INCLUDE_DIR}/gpmf-parser + PUBLIC + ${GMPF_PARSER_PUBLIC_INCLUDE_DIR} +) diff --git a/demo/GPMF_mp4reader.c b/src/GPMF_mp4reader.c similarity index 98% rename from demo/GPMF_mp4reader.c rename to src/GPMF_mp4reader.c index 6f754f1..f9efc67 100644 --- a/demo/GPMF_mp4reader.c +++ b/src/GPMF_mp4reader.c @@ -28,7 +28,7 @@ #include #include -#include "GPMF_mp4reader.h" +#include "gpmf-parser/GPMF_mp4reader.h" #define PRINT_MP4_STRUCTURE 0 @@ -221,7 +221,7 @@ size_t OpenMP4Source(char *filename, uint32_t traktype, uint32_t traksubtype, in #endif mp4->filesize = (uint64_t) mp4stat.st_size; // printf("filesize = %ld\n", mp4->filesize); - if (mp4->filesize < 64) + if (mp4->filesize < 64) { free(mp4); return 0; @@ -257,7 +257,7 @@ size_t OpenMP4Source(char *filename, uint32_t traktype, uint32_t traksubtype, in break; } - if (!VALID_FOURCC(qttag) && (qttag & 0xff) != 0xa9) // ©xyz and ©swr are allowed + if (!VALID_FOURCC(qttag) && (qttag & 0xff) != 0xa9) // �xyz and �swr are allowed { CloseSource((size_t)mp4); mp4 = NULL; @@ -291,7 +291,7 @@ size_t OpenMP4Source(char *filename, uint32_t traktype, uint32_t traksubtype, in nestsize[nest] = qtsize; lastsize = qtsize; -#if PRINT_MP4_STRUCTURE +#if PRINT_MP4_STRUCTURE for (int i = 1; i < nest; i++) printf("%5d ", nestsize[i]); //printf(" "); printf(" %c%c%c%c (%lld)\n", (qttag & 0xff), ((qttag >> 8) & 0xff), ((qttag >> 16) & 0xff), ((qttag >> 24) & 0xff), qtsize); @@ -333,7 +333,7 @@ size_t OpenMP4Source(char *filename, uint32_t traktype, uint32_t traksubtype, in } else { - + if (qttag == MAKEID('m', 'v', 'h', 'd')) //mvhd movie header { len = fread(&skip, 1, 4, mp4->mediafp); @@ -435,7 +435,7 @@ size_t OpenMP4Source(char *filename, uint32_t traktype, uint32_t traksubtype, in else if (i == 0) // If the first editlst starts after zero, the track is offset by this time (time before presentation time zero.) mp4->trak_edit_list_offsets[mp4->trak_num] -= (int32_t)((double)segment_mediaTime/(double)mp4->trak_clockdemon*(double)mp4->clockdemon); //convert to MP4 clock base. } - if (type == traktype) // GPMF metadata + if (type == traktype) // GPMF metadata { mp4->metadataoffset_clockcount = mp4->trak_edit_list_offsets[mp4->trak_num]; //leave in MP4 clock base } @@ -457,7 +457,7 @@ size_t OpenMP4Source(char *filename, uint32_t traktype, uint32_t traksubtype, in len += fread(&subtype, 1, 4, mp4->mediafp); // type will be 'meta' for the correct trak. if (len == 16) { - if (subtype != traksubtype) // not MP4 metadata + if (subtype != traksubtype) // not MP4 metadata { type = 0; // MP4 } @@ -855,7 +855,7 @@ size_t OpenMP4Source(char *filename, uint32_t traktype, uint32_t traksubtype, in LongSeek(mp4, qtsize - 8 - len); // skip over stco } else - if (type == traktype) // meta + if (type == traktype) // meta { uint32_t totaldur = 0, samples = 0; uint32_t entries = 0; @@ -870,7 +870,7 @@ size_t OpenMP4Source(char *filename, uint32_t traktype, uint32_t traksubtype, in mp4->meta_clockcount = mp4->trak_clockcount; - if(mp4->meta_clockdemon == 0) + if(mp4->meta_clockdemon == 0) { //prevent divide by zero CloseSource((size_t)mp4); @@ -923,7 +923,7 @@ size_t OpenMP4Source(char *filename, uint32_t traktype, uint32_t traksubtype, in CloseSource((size_t)mp4); mp4 = NULL; } - + // set the numbers of payload with both size and offset if (mp4 != NULL) { @@ -969,7 +969,7 @@ uint32_t GetVideoFrameRateAndCount(size_t handle, uint32_t *numer, uint32_t *dem void CloseSource(size_t handle) { mp4object *mp4 = (mp4object *)handle; - if (mp4 == NULL) + if (mp4 == NULL) { return; } @@ -994,7 +994,7 @@ void CloseSource(size_t handle) free(mp4->metastsc); mp4->metastsc = 0; } - + free(mp4); } @@ -1023,7 +1023,7 @@ uint32_t GetPayloadRationalTime(size_t handle, uint32_t index, int32_t *in_numer { mp4object *mp4 = (mp4object *)handle; if (mp4 == NULL) return MP4_ERROR_MEMORY; - + if (mp4->metaoffsets == 0 || mp4->basemetadataduration == 0 || mp4->meta_clockdemon == 0 || in_numerator == NULL || out_numerator == NULL) return MP4_ERROR_MEMORY; *in_numerator = (int32_t)(index * mp4->basemetadataduration); @@ -1037,7 +1037,7 @@ uint32_t GetPayloadRationalTime(size_t handle, uint32_t index, int32_t *in_numer *out_numerator += (int32_t)(((double)mp4->metadataoffset_clockcount / (double)mp4->clockdemon) * mp4->meta_clockdemon); *denominator = mp4->meta_clockdemon; - + return MP4_ERROR_OK; } @@ -1084,7 +1084,7 @@ size_t OpenMP4SourceUDTA(char *filename, int32_t flags) stat(filename, &mp4stat); #endif mp4->filesize = (uint64_t)mp4stat.st_size; - if (mp4->filesize < 64) + if (mp4->filesize < 64) { free(mp4); return 0; @@ -1183,4 +1183,3 @@ size_t OpenMP4SourceUDTA(char *filename, int32_t flags) } return (size_t)mp4; } - diff --git a/GPMF_parser.c b/src/GPMF_parser.c similarity index 99% rename from GPMF_parser.c rename to src/GPMF_parser.c index 9abb6db..75a08a2 100644 --- a/GPMF_parser.c +++ b/src/GPMF_parser.c @@ -1,13 +1,13 @@ /*! @file GPMF_parser.c - * + * * @brief GPMF Parser library * * @version 2.2.1 - * + * * (C) Copyright 2017-2020 GoPro Inc (http://gopro.com/). - * + * * Licensed under either: - * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 * - MIT license, http://opensource.org/licenses/MIT * at your option. * @@ -16,7 +16,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * + * */ #include @@ -24,9 +24,8 @@ #include #include -#include "GPMF_parser.h" -#include "GPMF_bitstream.h" - +#include "gpmf-parser/GPMF_bitstream.h" +#include "gpmf-parser/GPMF_parser.h" #ifdef DBG #if _WINDOWS @@ -80,7 +79,7 @@ GPMF_ERR GPMF_Validate(GPMF_stream *ms, GPMF_LEVELS recurse) uint32_t nestsize = ms->nest_size[ms->nest_level]; if (nestsize == 0 && ms->nest_level == 0) nestsize = ms->buffer_size_longs; - + while (ms->pos+1 < ms->buffer_size_longs && nestsize > 0) { uint32_t key = ms->buffer[ms->pos]; @@ -212,7 +211,7 @@ GPMF_ERR GPMF_ResetState(GPMF_stream *ms) return GPMF_OK; } - + return GPMF_ERROR_MEMORY; } @@ -244,7 +243,7 @@ GPMF_ERR GPMF_Init(GPMF_stream *ms, uint32_t *buffer, uint32_t datasize) return GPMF_ERROR_BAD_STRUCTURE; } } - + return GPMF_ERROR_MEMORY; } @@ -320,11 +319,11 @@ GPMF_ERR GPMF_Next(GPMF_stream *ms, GPMF_LEVELS recurse) } else { - return GPMF_ERROR_LAST; + return GPMF_ERROR_LAST; } } } - } + } while (ms->pos < ms->buffer_size_longs && ms->nest_size[ms->nest_level] > 0 && ms->buffer[ms->pos] == GPMF_KEY_END) { @@ -405,7 +404,7 @@ GPMF_ERR GPMF_Next(GPMF_stream *ms, GPMF_LEVELS recurse) // end of buffer return GPMF_ERROR_BUFFER_END; } - + size = (GPMF_DATA_SIZE(ms->buffer[ms->pos + 1]) >> 2); if (GPMF_OK != IsValidSize(ms, size)) @@ -451,7 +450,7 @@ GPMF_ERR GPMF_FindNext(GPMF_stream *ms, uint32_t fourcc, GPMF_LEVELS recurse) } } while (GPMF_OK == ret); - memcpy(ms, &prevstate, sizeof(GPMF_stream)); // restore read position + memcpy(ms, &prevstate, sizeof(GPMF_stream)); // restore read position return ret; // the error code returned from GPMF_Next() } else @@ -548,7 +547,7 @@ uint32_t GPMF_PayloadSampleCount(GPMF_stream *ms) while (GPMF_OK == GPMF_FindNext(&find_stream, fourcc, GPMF_CURRENT_LEVEL|GPMF_TOLERANT)) { count++; - } + } } else { @@ -637,7 +636,7 @@ GPMF_ERR GPMF_SeekToSamples(GPMF_stream *ms) else return GPMF_ERROR_BUFFER_END; } - else + else return GPMF_ERROR_MEMORY; } @@ -755,7 +754,7 @@ uint32_t GPMF_ElementsInStruct(GPMF_stream *ms) uint32_t tmpsize = sizeof(tmp); char *data = (char *)GPMF_RawData(&find_stream); uint32_t size = GPMF_RawDataSize(&find_stream); - + if (GPMF_OK == GPMF_ExpandComplexTYPE(data, size, tmp, &tmpsize)) return tmpsize; } @@ -917,7 +916,7 @@ void ByteSwap2Buffer(uint32_t* input, uint32_t* output, GPMF_SampleType data_typ { for (i = 0; i < (int32_t)((repeat * structSize + 3) / sizeof(int32_t)); i += 2) { - output[len++] = BYTESWAP32(input[i + 1]); + output[len++] = BYTESWAP32(input[i + 1]); output[len++] = BYTESWAP32(input[i]); } } @@ -938,7 +937,7 @@ void ByteSwap2Buffer(uint32_t* input, uint32_t* output, GPMF_SampleType data_typ //find and inplace overwrite a GPMF KLV with new KLV, if the lengths match. -GPMF_ERR GPMF_Modify(GPMF_stream* ms, uint32_t origfourCC, uint32_t newfourCC, +GPMF_ERR GPMF_Modify(GPMF_stream* ms, uint32_t origfourCC, uint32_t newfourCC, GPMF_SampleType newType, uint32_t newStructSize, uint32_t newRepeat, void* newData) { uint32_t dataSizeLongs = (newStructSize * newRepeat + 3) >> 2; @@ -997,12 +996,12 @@ GPMF_ERR GPMF_Modify(GPMF_stream* ms, uint32_t origfourCC, uint32_t newfourCC, } return GPMF_ERROR_BAD_STRUCTURE; // sizes don't match } - else + else { // search from the beginning through all levels GPMF_ResetState(&fs); if (GPMF_OK == GPMF_FindNext(&fs, origfourCC, GPMF_RECURSE_LEVELS|GPMF_TOLERANT)) - { + { tsr = fs.buffer[fs.pos + 1]; ssize = GPMF_SAMPLE_SIZE(tsr); repeat = GPMF_SAMPLES(tsr); @@ -1120,7 +1119,7 @@ uint32_t GPMF_SizeOfComplexTYPE(char *type, uint32_t typestringlength) for (i = 0; i < len; i++) if (typearray[i] == '[') expand = 1; - + if (expand) { uint32_t dstsize = sizeof(exptypearray); @@ -1166,7 +1165,7 @@ GPMF_ERR GPMF_FormattedData(GPMF_stream *ms, void *buffer, uint32_t buffersize, if (type == GPMF_TYPE_NEST) return GPMF_ERROR_BAD_STRUCTURE; - + if (GPMF_OK != IsValidSize(ms, remaining_sample_size>>2)) return GPMF_ERROR_BAD_STRUCTURE; @@ -1349,7 +1348,7 @@ GPMF_ERR GPMF_FormattedData(GPMF_stream *ms, void *buffer, uint32_t buffersize, case GPMF_TYPE_UNSIGNED_LONG: MACRO_CAST_SCALE_UNSIGNED_TYPE(uint32_t) break; \ case GPMF_TYPE_DOUBLE: MACRO_CAST_SCALE_SIGNED_TYPE(double) break; \ default: break; \ - } + } #define MACRO_CAST_UNSIGNED_SCALE \ switch (outputType) { \ @@ -1362,7 +1361,7 @@ GPMF_ERR GPMF_FormattedData(GPMF_stream *ms, void *buffer, uint32_t buffersize, case GPMF_TYPE_UNSIGNED_LONG: MACRO_CAST_SCALE_SIGNED_TYPE(uint32_t) break; \ case GPMF_TYPE_DOUBLE: MACRO_CAST_SCALE_SIGNED_TYPE(double) break; \ default: break; \ - } + } #define MACRO_BSWAP_CAST_SCALE(swap, inputcast, tempcast) \ { \ @@ -1697,7 +1696,7 @@ GPMF_ERR GPMF_ScaledData(GPMF_stream *ms, void *buffer, uint32_t buffersize, uin ret = GPMF_ERROR_SCALE_COUNT; goto cleanup; } - + GPMF_FormattedData(&fs, mtrx_buffer, mtrx_buffersize, 0, mtrx_count); mtrx_data = (uint32_t *)mtrx_buffer; break; @@ -1874,7 +1873,7 @@ GPMF_ERR GPMF_DecompressedSize(GPMF_stream *ms, uint32_t *neededsize) *neededsize = GPMF_DATA_SIZE(ms->buffer[ms->pos + 2]); // The first 32-bit of data, is the uncomresseded type-size-repeat return GPMF_OK; } - + return GPMF_ERROR_MEMORY; } @@ -1887,7 +1886,7 @@ GPMF_ERR GPMF_Decompress(GPMF_stream *ms, uint32_t *localbuf, uint32_t localbuf_ if (GPMF_OK != GPMF_AllocCodebook(&ms->cbhandle)) return GPMF_ERROR_MEMORY; - memset(localbuf, 0, localbuf_size); + memset(localbuf, 0, localbuf_size); // unpack here GPMF_SampleType type = (GPMF_SampleType)GPMF_SAMPLE_TYPE(ms->buffer[ms->pos + 2]);// The first 32-bit of data, is the uncomresseded type-size-repeat @@ -1897,7 +1896,7 @@ GPMF_ERR GPMF_Decompress(GPMF_stream *ms, uint32_t *localbuf, uint32_t localbuf_ uint16_t *compressed_data; uint32_t sample_size = GPMF_SAMPLE_SIZE(ms->buffer[ms->pos + 2]); uint32_t sizeoftype = GPMF_SizeofType(type); - if(sizeoftype == 0) + if(sizeoftype == 0) return GPMF_ERROR_MEMORY; uint32_t chn = 0, channels = sample_size / sizeoftype; uint32_t compressed_size = GPMF_DATA_PACKEDSIZE(ms->buffer[ms->pos + 1]); @@ -1918,7 +1917,7 @@ GPMF_ERR GPMF_Decompress(GPMF_stream *ms, uint32_t *localbuf, uint32_t localbuf_ if (type == 'l') type = GPMF_TYPE_SIGNED_SHORT; else - type = GPMF_TYPE_UNSIGNED_SHORT; + type = GPMF_TYPE_UNSIGNED_SHORT; } @@ -1935,7 +1934,7 @@ GPMF_ERR GPMF_Decompress(GPMF_stream *ms, uint32_t *localbuf, uint32_t localbuf_ if(sample_size > compressed_size) return GPMF_ERROR_MEMORY; - + memcpy(&buf_u8[0], start, sample_size); sOffset += sample_size; @@ -1955,7 +1954,7 @@ GPMF_ERR GPMF_Decompress(GPMF_stream *ms, uint32_t *localbuf, uint32_t localbuf_ case 1: last = buf_u8[chn]; quant = *((uint8_t *)&start[sOffset]); sOffset++; break; case 2: last = BYTESWAP16(buf_u16[chn]); quant = *((uint16_t *)&start[sOffset]); quant = BYTESWAP16(quant); sOffset += 2; break; } - + sOffset = ((sOffset + 1) & (uint32_t)~1); //16-bit aligned compressed data if (sOffset >= compressed_size) @@ -1980,7 +1979,7 @@ GPMF_ERR GPMF_Decompress(GPMF_stream *ms, uint32_t *localbuf, uint32_t localbuf_ last += delta * cb[currWord].bytes_stored; - if (channels * (pos + zeros) * sizeoftype > localbuf_size) + if (channels * (pos + zeros) * sizeoftype > localbuf_size) return GPMF_ERROR_MEMORY; switch ((int)sizeoftype * signed_type) @@ -2003,7 +2002,7 @@ GPMF_ERR GPMF_Decompress(GPMF_stream *ms, uint32_t *localbuf, uint32_t localbuf_ buf_u16[channels*pos + chn] = BYTESWAP16(last); break; } - + pos += (uint32_t) cb[currWord].bytes_stored; currWord <<= usedbits; currBits -= usedbits; @@ -2049,7 +2048,7 @@ GPMF_ERR GPMF_Decompress(GPMF_stream *ms, uint32_t *localbuf, uint32_t localbuf_ { int needed = 16 - currBits; currWord |= nextWord >> currBits; - if (nextBits >= needed) currBits = 16; else currBits += nextBits; + if (nextBits >= needed) currBits = 16; else currBits += nextBits; nextWord <<= needed; nextBits -= needed; if (nextBits <= 0) @@ -2064,7 +2063,7 @@ GPMF_ERR GPMF_Decompress(GPMF_stream *ms, uint32_t *localbuf, uint32_t localbuf_ if((channels * pos * sizeoftype) >= localbuf_size) return GPMF_ERROR_MEMORY; - + switch ((int)sizeoftype*signed_type) { default: @@ -2080,7 +2079,7 @@ GPMF_ERR GPMF_Decompress(GPMF_stream *ms, uint32_t *localbuf, uint32_t localbuf_ last += delta; buf_s8[channels*pos++ + chn] = (int8_t)last; break; - case 1: + case 1: delta = (int8_t)(currWord >> 8); delta *= quant; last += delta; @@ -2099,7 +2098,7 @@ GPMF_ERR GPMF_Decompress(GPMF_stream *ms, uint32_t *localbuf, uint32_t localbuf_ break; default: //Invalid codeword read - end = 1; + end = 1; return GPMF_ERROR_MEMORY; break; } @@ -2122,7 +2121,7 @@ GPMF_ERR GPMF_Decompress(GPMF_stream *ms, uint32_t *localbuf, uint32_t localbuf_ } } } while (!end); - + if (nextBits == 16) compressed_data--; sOffset = (size_t)compressed_data - (size_t)start; end = 0; @@ -2150,7 +2149,7 @@ GPMF_ERR GPMF_AllocCodebook(size_t *cbhandle) int zeros = 0, used = 0; cb->command = 0; - + // all commands are 16-bits long if (code == enccontrolcodestable.entries[HUFF_ESC_CODE_ENTRY].bits) { @@ -2170,7 +2169,7 @@ GPMF_ERR GPMF_AllocCodebook(size_t *cbhandle) cb++; continue; } - + for (z = enczerorunstable.length-1; z >= 0; z--) { if (16 - used >= enczerorunstable.entries[z].size) @@ -2194,7 +2193,7 @@ GPMF_ERR GPMF_AllocCodebook(size_t *cbhandle) mask >>= 1; } - //move the code word up to see if is a complete code for a value following the zeros. + //move the code word up to see if is a complete code for a value following the zeros. code <<= used; cb->bytes_stored = 0; @@ -2212,7 +2211,7 @@ GPMF_ERR GPMF_AllocCodebook(size_t *cbhandle) } } } - + if (used == 0) { used = 16; @@ -2254,4 +2253,4 @@ GPMF_ERR GPMF_Free(GPMF_stream* ms) return GPMF_OK; } return GPMF_ERROR_MEMORY; -} \ No newline at end of file +} diff --git a/GPMF_utils.c b/src/GPMF_utils.c similarity index 97% rename from GPMF_utils.c rename to src/GPMF_utils.c index 6959a67..2eeb05b 100644 --- a/GPMF_utils.c +++ b/src/GPMF_utils.c @@ -5,9 +5,9 @@ * @version 1.2.0 * * (C) Copyright 2020 GoPro Inc (http://gopro.com/). - * + * * Licensed under either: - * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 * - MIT license, http://opensource.org/licenses/MIT * at your option. * @@ -18,19 +18,18 @@ * limitations under the License. * */ - + #include #include #include #include -#include "GPMF_parser.h" -#include "GPMF_utils.h" - +#include "gpmf-parser/GPMF_parser.h" +#include "gpmf-parser/GPMF_utils.h" double GetGPMFSampleRate(mp4callbacks cb, uint32_t fourcc, uint32_t timeBaseFourCC, uint32_t flags, double *firstsampletime, double *lastsampletime) { - if (cb.mp4handle == 0) + if (cb.mp4handle == 0) return 0.0; uint32_t indexcount = cb.cbGetNumberPayloads(cb.mp4handle); @@ -96,7 +95,7 @@ double GetGPMFSampleRate(mp4callbacks cb, uint32_t fourcc, uint32_t timeBaseFour GPMF_stream any_stream; if (GPMF_OK == GPMF_Init(&any_stream, payload, payloadsize)) { - basetimestamp = starttimestamp; + basetimestamp = starttimestamp; if (timeBaseFourCC) { @@ -119,7 +118,7 @@ double GetGPMFSampleRate(mp4callbacks cb, uint32_t fourcc, uint32_t timeBaseFour } } } - //Note: basetimestamp is used the remove offset from the timestamp, + //Note: basetimestamp is used the remove offset from the timestamp, // however 0.0 may not be the same zero for your video or audio presentation time (although it should be close.) // On GoPro camera, metadata streams like SHUT and ISOE are metadata fields associated with video, and these can be used // to accurately sync meta with video. @@ -145,7 +144,7 @@ double GetGPMFSampleRate(mp4callbacks cb, uint32_t fourcc, uint32_t timeBaseFour for (i = teststart; i <= testend; i++) { payloadsize = cb.cbGetPayloadSize(cb.mp4handle, i); - payload = cb.cbGetPayload(cb.mp4handle, payloadres, i); + payload = cb.cbGetPayload(cb.mp4handle, payloadres, i); if (GPMF_OK == GPMF_Init(ms, payload, payloadsize)) if (GPMF_OK == GPMF_FindNext(ms, fourcc, GPMF_RECURSE_LEVELS | GPMF_TOLERANT)) endsamples += GPMF_PayloadSampleCount(ms); @@ -198,7 +197,7 @@ double GetGPMFSampleRate(mp4callbacks cb, uint32_t fourcc, uint32_t timeBaseFour intercept = (double)-startin * rate; } - else // for increased precision, for older GPMF streams sometimes missing the total sample count + else // for increased precision, for older GPMF streams sometimes missing the total sample count { uint32_t payloadpos = 0, payloadcount = 0; double slope, top = 0.0, bot = 0.0, meanX = 0, meanY = 0; @@ -265,8 +264,8 @@ double GetGPMFSampleRate(mp4callbacks cb, uint32_t fourcc, uint32_t timeBaseFour } } - // Compute the line of best fit for a jitter removed sample rate. - // This does assume an unchanging clock, even though the IMU data can thermally impacted causing small clock changes. + // Compute the line of best fit for a jitter removed sample rate. + // This does assume an unchanging clock, even though the IMU data can thermally impacted causing small clock changes. // TODO: Next enhancement would be a low order polynominal fit the compensate for any thermal clock drift. if (repeatarray) { @@ -353,4 +352,3 @@ double GetGPMFSampleRate(mp4callbacks cb, uint32_t fourcc, uint32_t timeBaseFour if (payloadres) cb.cbFreePayloadResource(cb.mp4handle, payloadres); return rate; } -