ADTF 录制文件格式

ADTF recording file format

本文关键字:格式 文件 ADTF      更新时间:2023-10-16

我正在用C++编写ADTF记录文件阅读器。我已经使用此处指定的结构读取了标题https://support.digitalwerk.net/adtf_libraries/adtf-streaming-library/v2/DATFileFormatSpecification.pdf

typedef struct tagFileHeader { 
    int ui32FileId;
    int ui32VersionId;
    int ui32Flags;
    int ui32ExtensionCount;
    long long ui64ExtensionOffset;
    long long ui64DataOffset;
    long long ui64DataSize;
    long long ui64ChunkCount;
    long long ui64MaxChunkSize;
    long long ui64Duration;
    long long ui64FileTime;
    char ui8HeaderByteOrder;     
    long long ui64TimeOffset;
    char ui8PatchNumber;
    char _reserved[54];
    char strDescription[1912]; 
} tFileHeader;   // size is 2048 Bytes

我读了赫德

ifstream file("myfile.dat", std::ifstream::binary);
char buffer[2048];
file.read(buffer, 2048);
const tagFileHeader* header = reinterpret_cast<const tagFileHeader*>(buffer);

现在我需要阅读这些块。这是从同一文档中提取的块标头

typedef struct tagChunkHeader { 
    long long ui64TimeStamp;
    int ui32RefMasterTableIndex;     
    int ui32OffsetToLast;     
    int ui32Size;     
    short ui16StreamId;     
    short ui16Flags;     
    long long ui64StreamIndex; 
} tChunkHeader;  // size is 32 Bytes

读取块

for (int c = 0; c < header->ui64ChunkCount; ++c)
{
    char chunkHeaderBuffer[32];
    file.read(chunkHeaderBuffer, 32);
    const tChunkHeader* chunk = reinterpret_cast<const tChunkHeader*>(chunkHeaderBuffer);
    //Skeep chunk data
    file.seekg(chunk->ui32Size, ios_base::cur);
}

我不知道如何解释块数据。这是否在我缺少的另一个文档中指定?谢谢

为了完整起见:

区块数据布局取决于原始示例数据和使用的序列化。因此,没有单一的数据布局。您必须使用正确的反序列化实现反序列化区块数据,然后可以使用正确的结构定义解释反序列化数据。有关所用序列化的信息存储在流的索引扩展中。

正如 C-3PFLO 已经说过的,adtf_file库可以为您完成所有这些工作,但您需要所有必需的反序列化器插件。

下面是一个示例(基于即将推出的 ADTF 文件库 0.5.0(如何访问 dat 文件并使用其他 adtffileplugins 扩展读取器。使用此读取数据文件,其中包含例如用ADTF 2.x记录的flexray数据:

/**
 * @file
 * ADTF File Access example
 *
 * @copyright
 * @verbatim
   Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
       This Source Code Form is subject to the terms of the Mozilla
       Public License, v. 2.0. If a copy of the MPL was not distributed
       with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
   If it is not possible or desirable to put the notice in a particular file, then
   You may include the notice in a location (such as a LICENSE file in a
   relevant directory) where a recipient would be likely to look for such a notice.
   You may add additional accurate notices of copyright ownership.
   @endverbatim
 */
#include <adtf_file/standard_adtf_file_reader.h>
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <map>
// initalize ADTF File and Plugin Mechanism
static adtf_file::Objects oObjects;
static adtf_file::PluginInitializer oInitializer([]
{
    adtf_file::add_standard_objects();
});
void query_file_info(adtf_file::Reader& reader)
{
    using namespace adtf_file;
    //setup file version
    uint32_t ifhd_version = reader.getFileVersion();
    std::string adtf_version("ADTF 3 and higher");
    if (ifhd_version < ifhd::v400::version_id)
    {
        adtf_version = "below ADTF 3";
    }
    //begin print
    std::cout << std::endl << "File Header" << std::endl;
    std::cout << "------------------------------------------------------------------------------" << std::endl;
    std::cout << "File version      : " << reader.getFileVersion() << " - " << adtf_version << std::endl;
    std::cout << "Date              : " << reader.getDateTime().format("%d.%m.%y - %H:%M:%S") << std::endl;
    std::cout << "Duration          : " << reader.getDuration().count() << std::endl;
    std::cout << "Short description : " << getShortDescription(reader.getDescription()) << std::endl;
    std::cout << "Long description  : " << getLongDescription(reader.getDescription()) << std::endl;
    std::cout << "Chunk count       : " << reader.getItemCount() << std::endl;
    std::cout << "Extension count   : " << reader.getExtensions().size() << std::endl;
    std::cout << "Stream count      : " << reader.getStreams().size() << std::endl;
    std::cout << std::endl << "Streams" << std::endl;
    std::cout << "------------------------------------------------------------------------------" << std::endl;
    auto streams = reader.getStreams();
    for (const auto& current_stream : streams)
    {
        auto property_stream_type = std::dynamic_pointer_cast<const PropertyStreamType>(current_stream.initial_type);
        if (property_stream_type)
        {
            std::string stream_meta_type = property_stream_type->getMetaType();      
            std::cout << "Stream #" << current_stream.stream_id << " : " << current_stream.name << std::endl;
            std::cout << "    MetaType       : " << stream_meta_type << std::endl;
            property_stream_type->iterateProperties(
                [&](const char* name, 
                const char* type,
                const char* value) -> void
                {
                    std::cout << "        " << name << " - " << value << std::endl;
                });
        }
    }
}
class StreamsInfo 
{
    typedef std::map<uint16_t, std::chrono::microseconds> LastTimesMap;
    typedef std::map<uint16_t, std::string> StreamNameMap;
    public:
        StreamsInfo(adtf_file::Reader& reader)
        {
            auto streams = reader.getStreams();
            for (auto current_stream : streams)
            {
                _map_stream_name[current_stream.stream_id] = current_stream.name;
                UpdateType(current_stream.stream_id, current_stream.initial_type);
            }
        }
        ~StreamsInfo() = default;
       std::string GetDiffToLastChunkTime(const uint16_t& stream_id, const std::chrono::microseconds& current_time)
        {
            return GetLastTimeStamp(_map_last_chunk_time, stream_id, current_time);
        }
        std::string GetDiffToLastSampleStreamTime(const uint16_t& stream_id, const std::chrono::microseconds& current_time)
        {
            return GetLastTimeStamp(_map_last_stream_time, stream_id, current_time);
        }
        std::string GetStreamName(const uint16_t& stream_id)
        {
            return _map_stream_name[stream_id];
        }
        void UpdateType(const uint16_t& stream_id, const std::shared_ptr<const adtf_file::StreamType>& type)
        {
            auto property_stream_type = std::dynamic_pointer_cast<const adtf_file::PropertyStreamType>(type);
            if (property_stream_type)
            {
                 _map_stream_meta_type[stream_id] = property_stream_type->getMetaType();
            }
        }
        std::string GetLastStreamMetaType(const uint16_t& stream_id)
        {
            return _map_stream_meta_type[stream_id];
        }
    private:
        std::string GetLastTimeStamp(LastTimesMap& map_last_times,
                                                   const uint16_t& stream_id,
                                                   const std::chrono::microseconds& current_time)
        {
            std::chrono::microseconds result(-1);
            LastTimesMap::iterator it = map_last_times.find(stream_id);
            if (it != map_last_times.end())
            {
                result = current_time - it->second;
                it->second = current_time;
            }
            else
            {
                if (current_time.count() != -1)
                {
                    map_last_times[stream_id] = current_time;
                }
            }
            if (result.count() >= 0)
            {
                return a_util::strings::format("%lld", result.count());
            }
            else
            {
                return "";
            }
        }
        LastTimesMap _map_last_chunk_time;
        LastTimesMap _map_last_stream_time;
        StreamNameMap _map_stream_name;
        StreamNameMap _map_stream_meta_type;
};

void access_file_data(adtf_file::Reader& reader, const std::string& csv_file_path)
{
    using namespace adtf_file;
    //load stream information
    StreamsInfo stream_info(reader);
    std::cout << std::endl << "File data" << std::endl;
    std::cout << "------------------------------------------------------------------------------" << std::endl;
    utils5ext::File csv_file;
    csv_file.open(csv_file_path, utils5ext::File::om_append | utils5ext::File::om_write);
    //set the labels
    csv_file.writeLine("stream;stream_name;chunk_type;stream_type;chunk_time;samplestream_time;chunk_time_delta_to_lastofstream;samplestream_time_delta_to_lastofstream");
    size_t item_count = 0;
    for (;; ++item_count)
    {
        try
        {
            auto item = reader.getNextItem();
            std::chrono::microseconds chunk_time = item.time_stamp;
            std::string chunk_type;
            auto type = std::dynamic_pointer_cast<const StreamType>(item.stream_item);
            auto data = std::dynamic_pointer_cast<const Sample>(item.stream_item);
            auto trigger = std::dynamic_pointer_cast<const Trigger>(item.stream_item);
            std::chrono::microseconds sample_time(-1);
            std::string sample_time_string("");
            if (type)
            {
                //the type change is part of the 
                chunk_type = "stream_type";
                stream_info.UpdateType(item.stream_id,
                                       type);
            }
            else if (data)
            {
                chunk_type = "sample";
                auto sample_data = std::dynamic_pointer_cast<const DefaultSample>(data);
                if (sample_data)
                {
                    sample_time = sample_data->getTimeStamp();
                    sample_time_string = a_util::strings::format("%lld", sample_time.count());
                }
            }
            else if (trigger)
            {
                chunk_type = "trigger";
            }
            csv_file.writeLine(a_util::strings::format("%d;%s;%s;%s;%lld;%s;%s;%s",
                static_cast<int>(item.stream_id),
                stream_info.GetStreamName(item.stream_id).c_str(),
                chunk_type.c_str(),
                stream_info.GetLastStreamMetaType(item.stream_id).c_str(),
                chunk_time.count(),
                sample_time_string.c_str(),
                stream_info.GetDiffToLastChunkTime(item.stream_id, chunk_time).c_str(),
                stream_info.GetDiffToLastSampleStreamTime(item.stream_id, sample_time).c_str()
                ));
        }
        catch (const exceptions::EndOfFile&)
        {
            break;
        }
    }
    csv_file.close();
}
adtf_file::Reader create_reader(const a_util::filesystem::Path& adtfdat_file_path)
{
    //open file -> create reader from former added settings
    adtf_file::Reader reader(adtfdat_file_path,
                             adtf_file::getFactories<adtf_file::StreamTypeDeserializers,
                                                     adtf_file::StreamTypeDeserializer>(),
                             adtf_file::getFactories<adtf_file::SampleDeserializerFactories,
                                                     adtf_file::SampleDeserializerFactory>(),
                             std::make_shared<adtf_file::sample_factory<adtf_file::DefaultSample>>(),
                             std::make_shared<adtf_file::stream_type_factory<adtf_file::DefaultStreamType>>());
    return reader;
}
int main(int argc, char* argv[])
{
    if (argc < 3 || argv[1] == NULL || argv[2] == NULL)
    {
        std::cerr << "usage: " << argv[0] << " <adtfdat> <csv> [<adtffileplugin> ...]" << std::endl;
        return -1;
    }
    //set path for adtfdat|dat and csv file
    a_util::filesystem::Path adtfdat_file = argv[1];
    a_util::filesystem::Path csv_file = argv[2];
    try
    {
        //verify adtf|dat file
        if (("adtfdat" != adtfdat_file.getExtension())
            && ("dat" != adtfdat_file.getExtension()))
        {
            throw std::runtime_error(adtfdat_file + " is not valid, please use .adtfdat (ADTF 3.x) or .dat (ADTF 2.x).");
        }
        //verify csv file
        if ("csv" != csv_file.getExtension())
        {
            throw std::runtime_error(csv_file + " is not valid, please use .csv for sample data export.");
        }
        //check for additional adtffileplugins
        for (int i = 3; i < argc; i++)
        {
            a_util::filesystem::Path adtffileplugin = argv[i];
            if ("adtffileplugin" == adtffileplugin.getExtension())
            {
                adtf_file::loadPlugin(adtffileplugin);
            }
        }
        //setup reader
        auto reader = create_reader(adtfdat_file);
        //print information about adtfdat|dat file
        query_file_info(reader);
        //export sample data
        access_file_data(reader, csv_file);
    }
    catch (const std::exception& ex)
    {
        std::cerr << ex.what() << std::endl;
        return -2;
    }
    return 0;
}

有什么理由尝试重新实现 ADTF DAT 文件读取器吗?它将由 ADTF 流库提供,并应提供访问存储在 dat 文件中的任何数据。请参阅文件访问示例 (https://support.digitalwerk.net/adtf_libraries/adtf-streaming-library/v2/api/page_fileaccess.html( 如何使用读取器以及 API 本身和所有其他示例。

提示:您还可以使用具有相同可能性的后续 - ADTF 文件库,但还有两个好处:完整的开源以查看 (adtf(dat 文件处理的工作原理,并支持使用 ADTF 3.x 创建的文件。请参阅 https://support.digitalwerk.net/adtf_libraries/adtf-file-library/v0/html/index.html

对于那些有兴趣下载流媒体库的人,请点击以下链接

https://support.digitalwerk.net/projects/download-center/repository/show/adtf-libraries/adtf-streaming-library/release-2.9.0