【问题标题】:ADTF recording file formatADTF 录音文件格式
【发布时间】:2019-06-13 10:28:06
【问题描述】:

我正在用 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);
}

我不知道如何解释块数据。这是在我丢失的另一个文件中指定的吗? 谢谢

【问题讨论】:

  • cmets 中的一些附加信息发送至this question/answer
  • 我只有一个 versionID=0x0201 的 .dat 文件

标签: c++ adtf


【解决方案1】:

为了完整起见:

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

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

【讨论】:

    【解决方案2】:

    这是一个示例(基于即将推出的 ADTF 文件库 0.5.0)如何访问 dat 文件并使用附加的 adtffileplugins 扩展阅读器。使用此读取的 dat 文件,其中包含例如使用 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;
    }
    

    【讨论】:

    • 谢谢,这是我使用的代码。我只需要下载 flex ray 反序列化插件。
    【解决方案3】:

    您有什么理由尝试重新实现 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

    【讨论】:

    • 我尝试使用 DigitalWerk.net 提供的 ADTF 文件库读取文件,但在 adtf_file::Reader 构造函数中获得了此异常:'adtf.type.flexray.没有类型反序列化器。 adtf2_support.serialization.adtf.cid' 可用。哪里可以下载库的代码?
    • 好吧,得到错误或异常并不意味着重新实现不同的东西。这条信息很简单:读者不知道如何反序列化您录制的文件中来自 ADTF 2.x flexray 流类型的数据,因此您必须提供它(一如既往)。所以你必须通过添加设备工具箱提供的反序列化插件来扩展阅读器。将 support.digitalwerk.net/projects/download-center/repository/… 与 ADTF 文件库 0.4.x 或更高版本结合使用。
    • 谢谢,我刚刚发送电子邮件至 support@digitalwerk.net,以便在 Digitalwerk 社区注册并下载设备工具箱提供的 flexray 反序列化器插件。只是为了理解,ADTF文件的格式规范不是完全开放的吗?我在任何地方都找不到这个问题的明确答案。
    • 格式开放发布,我只是想推荐你使用提供的库,这样你就不用重新发明轮子了。此外,如果您缺少某些东西,您可以在 ADTF 文件库中自己完成,这些示例只是演示,它显示了事情是如何进行的。有关格式,请参阅 support.digitalwerk.net/adtf_libraries/adtf-streaming-library/…support.digitalwerk.net/adtf/v2/adtf_sdk_html_docs/…,对于 ADTF 3.x 中的 adtfdat,它仍然缺失,但这与您的用例无关。
    • 谢谢,我不想重新实现任何东西,我只是了解哪些是我的选择。我没有找到块数据的格式。你知道它是在哪里指定的吗?
    【解决方案4】:

    【讨论】:

      猜你喜欢
      • 2012-09-08
      • 1970-01-01
      • 1970-01-01
      • 2011-06-19
      • 1970-01-01
      • 1970-01-01
      • 2014-02-13
      • 2010-11-24
      • 1970-01-01
      相关资源
      最近更新 更多