[返回博客](/cn/blog) # 使用 Visualize Streaming

Egor Slupko 九月 17, 2021 [\#Visualize](/cn/blog/tag/visualize) [\#getting started](/cn/blog/tag/getting-started)

<a class="a2a_button_facebook"></a><a class="a2a_button_twitter"></a><a class="a2a_button_linkedin"></a>

#### 概述

Visualize SDK 文件格式 VSFX 具有内置流式传输支持。这意味着如果 VSFX 文件可以作为一组二进制数组提供，Visualize SDK 可以一致地处理这些数组并使用这些数组中的内容生成 Visualize 数据库。此外，通过提供“足够”的数组，甚至可以渲染不完整的数据库。请注意，Visualize SDK 不会将解析后的数据保留在内存中，因此不完整的数据库仅在内存中保留源数据中未解析的部分。但是，由于某些限制，常规 VSFX 文件在高效流式传输之前应进行预处理。本文介绍了预处理阶段和收集数据库数据的过程。

#### VSFX 预处理

##### 流式兼容性

VSFX 文件可以表示为一组节。所有节可分为两组：对象节（包含可视化对象数据：实体、几何体、设备等）和服务节（描述如何解析对象节）。

服务节依赖于对象节，因此当您生成 VSFX 文件时，服务节会放置在对象节之后。流式传输此类文件完全无效：只有在文件全部内容流式传输完毕后，Visualize SDK 才能读取它。此类文件称为流式不兼容文件。

OdTvDatabaseReceiver 具有静态方法，可以检查 VSFX 文件是否流式兼容，并且具有可以将流式不兼容的 VSFX 文件转换为流式兼容文件的方法：

```
static bool isStreamingCompatible( const OdString& fileName, OdTvResult* pRes = NULL );
static bool isStreamingCompatible( OdStreamBuf* pBuffer, OdTvResult* pRes = NULL );
static OdTvResult makeStreamingCompatible( const OdString& input, const OdString& output );
static OdTvResult makeStreamingCompatible( OdStreamBuf* pInput, OdStreamBuf* pOutput );
```

转换为流式兼容文件是一个足够快的进程，因为 Visualize SDK 只交换 VSFX 文件节而不解析其内容。

此外，通用的 Visualize SDK VSFX 文件读取方法在流式兼容和流式不兼容情况下都同样有效。

下图显示了流式兼容和流式不兼容情况下节位置的差异：

![streaming-friendly](/files/inline-images/streaming%20compatible.png)##### 流友好文件

VSFX 流式传输的主要目标是在仅解析 VSFX 文件的一部分时渲染可视化数据库。然而，除了可渲染对象（实体、几何体、插入）之外，对象节还包含渲染所需的其他对象：设备、视图、线型等。因此，渲染一个未接收所有必需对象的不完整数据库可能是不可能的（未解析设备或视图），或者可能产生与渲染完整数据库显著不同的结果（错误的颜色、线型等）。

在流友好 VSFX 文件中，对象节的构成方式是所有渲染所需的对象都放置在可渲染对象之前。在解析完所有必需对象后，这些文件可以正确渲染。

在非流友好 VSFX 文件中，也可以渲染不完整的数据库，但在这种情况下，客户端应用程序需要确保数据库已解析所有必要的对象。例如，它可以检查设备和视图迭代器、线型迭代器等。

通用的 VSFX 文件写入方法总是生成流友好的内容。然而，卸载数据库部分对象（例如低内存导入）可能会生成非流友好文件。

isStreamingFriendlySource() 方法检查数据解析是否流友好，如果返回 true，则 isDatabaseRenderable() 方法通知数据库可以安全渲染。

假设一个对象节包含四种类型的数据：设备、图层、实体和几何体。设备和图层数据是渲染所必需的。因此，如果某些图层具有颜色，则在这些图层未在实体渲染之前加载的情况下（因为在这种情况下使用默认图层），分配了“按图层着色”的图层上的实体将渲染不正确。其余数据——实体和几何体——是可渲染数据。当加载可渲染对象时，渲染场景会获得更多细节，但如果其中一些对象缺失，它们将不会被绘制，并且不会影响先前绘制的对象。

下图显示了所描述示例中流友好和非流友好情况之间的差异：

![the difference between streaming-friendly and non-streaming-friendly cases](/files/inline-images/streaming%20friendly.png)#### 在客户端应用程序中收集数据库

在客户端收集数据库：

1. 使用 OdTvFactory 实例创建 OdTvDatabaseReceiver 实例：
    ```
    OdTvFactoryId factId = odTvGetFactory();
    OdTvDatabaseReceiverPtr pDbReceiver = factId.createDatabaseReceiver();
    ```
2. 接收器应处理每个输入数据数组：
    ```
    /*Input: 
        const OdUint8* pData; //.VSFX 文件的一部分
        OdUInt32 nDataSize; //pData 数组的长度
    */
    bool bDone = pDbReceiver->doReceive( pData, nDataSize);
    ```
3. 如果数据库完全接收，doReceive 方法返回 true。在这种情况下，数据接收过程可以停止。否则，应用程序应决定不完整的数据库是否已准备好进行渲染。首先，检查由 DatabaseReceivingState 枚举值表示的接收状态：
    ```
    OdTvDatabaseReceiver::DatabaseReceivingState state = pDbReceiver->state();
    ```

     状态可以是以下之一：
    - OdTvDatabaseReceiver::kReceiver\_Nothing — 未接收到任何内容；数据库为空。
    - OdTvDatabaseReceiver::kReceiver\_AwaitingServiceData — 数据解析已开始，但目前即使是服务部分也不完整，因此数据库仍然为空。
    - OdTvDatabaseReceiver::kReceiver\_AwaitingObjectsData — 数据解析已开始，并且所有服务部分都已接收；从这个状态开始，应用程序可以访问数据库并尝试渲染其内容。
    - OdTvDatabaseReceiver::kReceiver\_Complete — 数据库已完全接收，并准备好进行进一步处理，不受限制。

    如果状态低于 OdTvDatabaseReceiver::kReceiver\_AwaitingObjectsData，应用程序应继续接收数据而不进行数据库处理；如果状态高于 OdTvDatabaseReceiver::kReceiver\_AwaitingObjectsData，则数据库已完全接收。

    如果状态是 OdTvDatabaseReceiver::kReceiver\_AwaitingObjectsData（因为在大多数情况下，VSFX 文件的最大部分包含对象部分），应用程序应检查 VSFX 源是否支持流式传输，如果是，应用程序可以使用 isDatabaseRenderable() 方法检查它是否可以渲染数据库：

    ```
    if( state == OdTvDatabaseReceiver::kReceiver_AwaitingObjectsData )
    {
        if( pDbReceiver->isStreamingFriendlySource() ) return pDbReceiver->isDatabaseRenderable();
    }
    ```
4. OdTvDatabaseReceiver::kReceiver\_Nothing — 未接收到任何内容；数据库为空。
5. OdTvDatabaseReceiver::kReceiver\_AwaitingServiceData — 数据解析已开始，但目前即使是服务部分也不完整，因此数据库仍然为空。
6. OdTvDatabaseReceiver::kReceiver\_AwaitingObjectsData — 数据解析已开始，并且所有服务部分都已接收；从这个状态开始，应用程序可以访问数据库并尝试渲染其内容。
7. OdTvDatabaseReceiver::kReceiver\_Complete — 数据库已完全接收，并准备好进行进一步处理，不受限制。
8. 如果 VSFX 源文件不支持流式传输，应用程序应手动检查它是否可以打开渲染所需的所有对象。例如，以下代码检查数据库是否包含第一个设备和其中至少一个视图：
    ```
    OdTvDatabaseId dbID = pDbReceiver->database();
    OdTvDatabasePtr pDb = dbID.openObject( OdTv::kForRead );
    if( pDb.isNull() ) return false;
    OdTvDevicesIteratorPtr pDevIt = pDb->getDevicesIterator();
    if( pDevIt.isNull() ) return false;
    OdTvGsDeviceId devId = pDevIt->getDevice();
    if( devId.isNull() ) return false;
    OdTvGsDevicePtr pDevice = devId.openObject( OdTv::kForRead );
    bool anyView = false;
    OdTvResult tvRes = tvOk;
    int nViews = pDevice->numViews( &tvRes );
    if( tvRes != tvOk || nViews == 0 ) return false;
    for( int i = 0; i < nViews; ++i )
    {
      if( !pDevice->viewAt( i ).isNull() ) anyView = true;
    }
    return anyView;
    ```

#### 示例

OdVisualizeFirstApp 示例应用程序实现了一个流式传输工具。由于它不是网络应用程序，它通过从 VSFX 文件读取二进制数据块来模拟流式传输。它还对输入 VSFX 文件进行了流式传输兼容性检查和转换，这通常应在服务器端实现。

要在 OdVisualizeFirstApp 应用程序中启用流式传输工具，需要在 CommonApplications/Visualize/Examples/win/OdVisualizeFirstApp/resource.h 中取消注释 OD\_VISUALIZE\_APP\_ENABLE\_STREAMING 定义。示例代码位置：OdVisualizeAppStreaming.h 和 OdVisualizeAppStreaming.cpp。

## 今天就开始行动

**免费试用 ODA 软件 60 天。  
无风险，无需信用卡。**

[免费试用](https://www.opendesign.com/cn/free-trial)
