メイン・コンテンツまでスキップ

ビデオ・デコーディング

このセクションでは、ビデオ・デコーディング機能を備えたTouchGFX HALを生成するためのTouchGFX Generatorの設定方法について説明します。

このシナリオを読む前に、TouchGFXでのMJPEGビデオの使用に関するドキュメントおよびビデオ・ウィジェット自体に関するドキュメントに目を通してください。

次のシナリオでは、ソフトウェア(LibJPEG)またはハードウェア(JPEG)のいずれかを使用してTouchGFX HALでビデオ・デコーディングをサポートできるようにする方法について詳しく説明します。 このシナリオでは、STM32F7とSTM32H7の両方について説明します。ハードウェア(JPEG)デコーディングをサポートするためのSTM32CubeMXの設定がSTM32F7では若干異なるからです。

特定のプロジェクト向けにマイクロコントローラを設定する前に、必ずこの記事のすべてのセクションをお読みください

通常、LibJPEG設定とJPEG設定は、STM32CubeMXの[Middleware]および[Multimedia]カテゴリに含まれています。

STM32CubeMXのJPEG設定とLibJPEG設定

Tip
  • STM32H750-DK、STM32F769-DISCOおよびSTM32F746G-DISCO TouchGFX Board Setup(TBS)の最新バージョンでは、STM32CubeMX設定によるソフトウェアとJPEGハードウェアの両方のデコーディングに対応しています。
  • 特定のマイクロコントローラでMJPEGビデオ・デコーディングをサポートするには、これらのサンプル・プロジェクトにあるSTM32CubeMX設定をヒントとして使用してください。
  • RTOSのサポート

    Generatorユーザガイドに記載されているように、シングル・バッファおよびダブル・バッファ・デコーディング戦略には、FreeRTOSなどのCMSIS準拠のRTOSが必要です。 TouchGFX GeneratorはvideoTaskFunc()エントリ・ポイント関数を生成します。この関数はビデオ・デコーディング・タスクと関連付ける必要があります。 STM32CubeMXでは、FreeRTOSミドルウェア設定の[Tasks and queues]タブでタスクとエントリ・ポイント関数を定義することにより、この設定を生成できます。

    ビデオ・タスク・スタック・サイズ(CMSIS V2の場合はワード数で定義)とRTOSヒープ・サイズは2つの重要な要素です。

    LibJPEGはダイナミック・メモリ割り当てを使用するため、ソフトウェア・デコーディングではスタック・サイズを慎重に設定する必要があります。 ハードウェア・デコーディングでは、メモリをダイナミックに割り当てるソフトウェア・スタックがないため、スタック・サイズを大幅に小さくすることができます。

    FreeRTOSヒープは汎用的なアプリケーション + 0xA000に対して十分な大きさがある必要があります。

    FreeRTOSタスクの設定

    FreeRTOSヒープ・サイズの設定

    上記の設定に基づいて、STM32CubeMXはビデオ・タスク用に次のコードを生成します。

    main.c
    /* Definitions for VideoTask */
    osThreadId_t VideoTaskHandle;
    const osThreadAttr_t VideoTask_attributes = {
    .name = "VideoTask",
    .stack_size = 1000 * 4,
    .priority = (osPriority_t) osPriorityLow,
    };
    ...
    void main()
    {
    ...
    /* creation of VideoTask */
    VideoTaskHandle = osThreadNew(videoTaskFunc, NULL, &VideoTask_attributes);
    ...
    }
    FreeRTOSConfig.h
    #define configTOTAL_HEAP_SIZE                    ((size_t)75000)

    ソフトウェア・デコーディング

    ソフトウェア・デコーディング・ソリューションでは、Generatorユーザガイドで定められているように、LibJPEGミドルウェアをSTM32CubeMXから有効化する必要があります。 ソフトウェア・デコーディングの設定は、すべてのLibJPEG対応マイクロコントローラ(STM32F4、STM32F7、STM32H7)で同じです。

    TouchGFX Software Decoderでは、LibJPEGでデコードされるデータのピクセル順序をBGRにする必要があります。 この設定がRGBのままの場合は、R色成分とB色成分がアプリケーション内でスワップされます。

    さらに、各ピクセルのサイズは、16ビットまたは24ビットのビデオRGBバッファを使用する場合は3バイト、32ビットのビデオRGBバッファを使用する場合は4バイトにする必要があります。

    16ビットまたは24ビットのビデオRGBバッファ用のLibJPEG設定

    Caution
  • RGB_ORDERINGの設定はBGRに設定し、ピクセル・サイズは使用するビデオRGBバッファのフォーマットに応じて設定する必要があります。
  • アプリケーションがARGB8888(32ビット)アプリケーションのDirect to Framebuffer戦略を使用している場合、ピクセル・サイズは4に設定する必要があります。
  • ビデオ・データ

    Caution
    STM32CubeMX、TouchGFX GeneratorおよびTouchGFX Designerのビデオ・ウィジェットを使用する現在のデコーディング・ソリューションは、現時点ではSTボードに対してのみ機能します。ビデオ・データは既知のメモリ・マップドFlashにある特定のアドレスでアプリケーションにリンクされるからです。

    EWARMプロジェクトの以下のコードは、TouchGFX Designerによって生成される追加オプションと、すべてのTouchGFX Board Packageについてリンカ・スクリプト内部に定義されているExtFlashSectionにデータが配置される方法を示しています。 これは、非メモリ・マップドFlashやこのセクションを定義しないプロジェクトでは機能しません。

    ewarm_project.ewp
            <option>
    <name>IlinkExtraOptions</name>
    <state>--image_input $PROJ_DIR$\..\TouchGFX\generated\videos\bin\washerdryer.bin,video_washerdryer_bin_start,ExtFlashSection,4</state>
    <state>--keep video_washerdryer_bin_start</state>
    </option>

    非メモリ・マップド・メモリにビデオ・データが含まれているプロジェクトについては、この記事のFileReaderに関するセクションを参照してください。

    ハードウェア・デコーディング

    Generatorユーザガイドに記載されているように、ハードウェア・デコーディングを可能にするために、JPEG IPをSTM32CubeMXで有効にする必要があります。

    STM32F769-DISCO

    STM32F769などのJPEG対応STM32F7シリーズのJPEGの設定は、STM32H7シリーズとは若干異なります。 JPEG設定にあるRGB_FORMATの設定は、TouchGFXフレームバッファのピクセル・フォーマットに従う必要があります(下の例ではJPEG_RGB565)。

    JPEGのパラメータ設定

    JPEG設定にある[DMA Settings]タブから、DMAを使用して、データをJPEGペリフェラルに(メモリからペリフェラル)またはJPEGペリフェラルから(ペリフェラルからメモリ)送信します。 INOUTに対するDMAリクエストを追加すると、方向パラメータが自動的に設定されます。

    JPEG DMAの設定

    これでJPEG対応STM32F7(STM32F769など)に対するハードウェア・デコーディング用のTouchGFX HALの設定は終了です。 STM32CubeMXからコードを生成した後、Designerのビデオ・ウィジェットを使用すると、アプリケーションでJPEGペリフェラルを使用してビデオをデコードできるようになります。

    Caution
    JPEGペリフェラルのRGB_FORMATの設定は、TouchGFXフレームバッファのフォーマットに従う必要があります。

    STM32H750-DK

    たとえば、STM32H750とSTM32F769のハードウェア・デコーディング(JPEG対応)の違いは、STM32CubeMXでのDMA転送の設定方法だけです。 UIだけでなく、DMAコンセプトも異なります。

    STM32H750の場合、JPEGペリフェラルは、通常のDMAペリフェラルではなくMDMAペリフェラルを使用するようにのみ設定できます。 下の画像に示すように、入出力両方のFIFOしきい値信号のMDMA設定を追加します。

    Note
    MDMAは、DMA1/DMA2と比べてはるかに高性能のDMAエンジンです。

    JPEG DMAの設定

    JPEG DMAの設定

    FileReaderインタフェース

    MJPEGビデオを非メモリ・マップド・メモリに格納すると、開発者は、デコーディング用にデータを設定済みのデコーダ(ソフトウェア / ハードウェア)に渡すためにTouchGFXビデオ・コントローラで使用できるtouchgfx::VideoDataReaderの実装を指定できます。 以下に、ビデオ・データを1つのバッファから別のバッファにコピーするインタフェースなどの簡単な例を示します。

    VideoView.cpp
    class MyReader : public touchgfx::VideoDataReader
    {
    public:
    MyReader() : position(0) { }
    virtual uint32_t getDataLength() { return video_len; }
    virtual void seek(uint32_t pos) { position = pos; }
    virtual bool readData(void* dst, uint32_t bytes)
    {
    memcpy(dst, &video_data[position], bytes);
    position += bytes;
    return true;
    }
    private:
    uint32_t position;
    } myReader;

    Videoウィジェットでマップド・メモリ内のビデオの開始位置をポイントするかわりに、開発者はデータ・リーダを使用するようにウィジェットを設定できます。

    VideoView.cpp
    video.setVideoData(myReader);

    TBSを移行してビデオ・デコーディングに対応

    ビデオ・デコーディングをサポートするマイクロコントローラでTouchGFX Board Setup(TBS)から作成したプロジェクトを、ビデオ・デコーディングがサポートされる前のTouchGFX Designerのバージョンから移行し、そのプロジェクトでTouchGFX Designerの[Run Target]を使用できるようにしたい場合は、GCC Makefileにいくつかの変更を手動で加える必要があります。

    必要な変更の概要およびその変更が必要な理由については、後続のセクションで説明します。 常に適用する必要がある一般的な変更と、開発者のアプリケーションの使用内容に応じて、LibJPEG(ソフトウェア・デコーディング)やJPEG(ハードウェア・デコーディング)に固有の変更があります。 変更により、以前のTBSから作成された既存のGCC Makefileが拡張されます。

    Makefileの更新以外にも、上記のシナリオで説明したように、STM32CubeMXでビデオ・デコーディングを設定する必要があります。

    一般的な変更

    LIBJPEGパスをプロジェクトに定義します。

    # LibJPEG path
    libjpeg_path := $(cubemx_middlewares_path)/Third_Party/LibJPEG

    次に、ビデオ・アセット入力パスを定義します。

    asset_texts_input  := TouchGFX/assets/texts

    asset_videos_input := TouchGFX/assets/videos

    ビデオ・アセット出力パスも、既存のアセット出力パスの下に定義する必要があります。

    asset_images_output := $(asset_root_path)/images
    asset_fonts_output := $(asset_root_path)/fonts
    asset_texts_output := $(asset_root_path)/texts
    asset_videos_output := $(asset_root_path)/videos

    ビデオ出力アセットをコンポーネント・リストに追加します。

    all_components := $(components) \
    $(asset_fonts_output) \
    $(asset_images_output) \
    $(asset_texts_output)
    $(asset_texts_output) \
    $(asset_videos_output)

    ビデオ・オブジェクト・ファイルを定義します。 ビデオ・オブジェクト・ファイルは既存のオブジェクトから区別します。

    c_source_files := $(call find, $(source_paths),*.c) $(os_source_files) $(board_c_files)
    source_files += $(board_cpp_files)

    video_object_files := $(call find, $(asset_videos_output),*.o)

    ビデオ・コンバータ・スクリプトへのパスを定義します。

    textconvert_script_path := $(touchgfx_path)/framework/tools/textconvert
    textconvert_executable := $(call find, $(textconvert_script_path), *.rb)
    videoconvert_script_path := $(touchgfx_path)/framework/tools/videoconvert

    オプションでechoを追加して、すべてのビデオ・オブジェクト・ファイルを表示できます。 ビデオ・オブジェクト・ファイルをリンク設定ステージに追加します。 この行には他のオブジェクト・ファイルとともに追加される$(video_object_files)を指定します。

    $(binary_output_path)/$(target_executable): $(object_files) $(object_asm_files)
    @echo Video Objects: $(video_object_files)
    @echo Linking $(@)
    @mkdir -p $(@D)
    @mkdir -p $(object_output_path)
    @$(file >$(build_root_path)/objects.tmp) $(foreach F,$(object_files) $(video_object_files),$(file >>$(build_root_path)/objects.tmp,$F))

    ビデオ・ルールを既存のassetsと.PHONYに追加します。

    _assets_: BitmapDatabase TextKeysAndLanguages Videos

    .PHONY: BitmapDatabase TextKeysAndLanguages Videos

    ビデオ・ルールをビデオ変換とともに追加します。

    Videos:
    @ruby $(videoconvert_script_path)/videoconvert.rb $(asset_videos_input) $(asset_videos_output)

    最後に、クリーンなルールを更新して、ビデオ関連の出力も除去します。

    _clean_:
    @echo Cleaning: $(board_name)
    @rm -rf $(build_root_path)
    # Do not remove gui_generated
    @rm -rf $(asset_images_output)
    @rm -rf $(asset_fonts_output)
    @rm -rf $(asset_texts_output)
    @rm -rf $(asset_videos_output)
    # Create directory to avoid error if it does not exist
    @mkdir -p $(asset_root_path)
    # Remove assets folder if it is empty (i.e. no gui_generated folder)
    @rmdir --ignore-fail-on-non-empty $(asset_root_path)
    # Clean bootloader project
    @$(MAKE) -r -f ExtMem_Boot/gcc/Makefile -s $(MFLAGS) clean

    ソフトウェアの変更

    すべてのLIBJPEGパスをインクルード・パスに追加します。

    include_paths := $(library_includes) \
    $(foreach comp, $(all_components), $(comp)/include) \
    $(foreach comp, $(cubemx_components), $(comp)/Inc) \
    $(foreach comp, $(touchgfx_generator_components), $(comp)/generated) \
    $(framework_includes) \
    $(cubemx_middlewares_path) \
    $(touchgfx_middlewares_path) \
    $(touchgfx_generator_components) \
    LIBJPEG/Target \
    $(libjpeg_path)/include \
    LIBJPEG/App

    LIBJPEGソース・パスを定義します。

    c_source_files := $(call find, $(source_paths),*.c) $(os_source_files) $(board_c_files)
    source_files += $(board_cpp_files)

    libjpeg_source_path = Middlewares/Third_Party/LibJPEG/source

    次に、すべてのLIBJPEGソース・ファイルをboard_c_filesに追加します。

    oard_c_files := \
    $(Drivers_path)/BSP/STM32H750B-DK/stm32h750b_discovery_bus.c \
    $(Drivers_path)/BSP/STM32H750B-DK/stm32h750b_discovery_qspi.c \
    $(Drivers_path)/BSP/STM32H750B-DK/stm32h750b_discovery_sdram.c \
    $(Drivers_path)/BSP/STM32H750B-DK/stm32h750b_discovery_ts.c \
    $(Drivers_path)/BSP/Components/ft5336/ft5336.c \
    $(Drivers_path)/BSP/Components/ft5336/ft5336_reg.c \
    $(Drivers_path)/BSP/Components/mt25tl01g/mt25tl01g.c \
    $(Drivers_path)/BSP/Components/mt48lc4m32b2/mt48lc4m32b2.c \
    $(libjpeg_source_path)/jaricom.c \
    $(libjpeg_source_path)/jcomapi.c \
    $(libjpeg_source_path)/jdapimin.c \
    $(libjpeg_source_path)/jdapistd.c \
    $(libjpeg_source_path)/jdarith.c \
    $(libjpeg_source_path)/jdatasrc.c \
    $(libjpeg_source_path)/jdcoefct.c \
    $(libjpeg_source_path)/jdcolor.c \
    $(libjpeg_source_path)/jddctmgr.c \
    $(libjpeg_source_path)/jdhuff.c \
    $(libjpeg_source_path)/jdinput.c \
    $(libjpeg_source_path)/jdmainct.c \
    $(libjpeg_source_path)/jdmarker.c \
    $(libjpeg_source_path)/jdmaster.c \
    $(libjpeg_source_path)/jdmerge.c \
    $(libjpeg_source_path)/jdpostct.c \
    $(libjpeg_source_path)/jdsample.c \
    $(libjpeg_source_path)/jdtrans.c \
    $(libjpeg_source_path)/jerror.c \
    $(libjpeg_source_path)/jidctflt.c \
    $(libjpeg_source_path)/jidctfst.c \
    $(libjpeg_source_path)/jidctint.c \
    $(libjpeg_source_path)/jmemmgr.c \
    $(libjpeg_source_path)/jmemnobs.c \
    $(libjpeg_source_path)/jquant1.c \
    $(libjpeg_source_path)/jquant2.c \
    $(libjpeg_source_path)/jutils.c \
    LIBJPEG/App/libjpeg.c

    さらに、その他のミドルウェア・ソース・ファイルと同じ方法で、LIBJPEGソース・ファイルを既存のオブジェクト・ファイルに追加します。

    # Start converting paths
    object_files := $(object_files:$(touchgfx_path)/%.cpp=$(object_output_path)/touchgfx/%.o)
    object_files := $(object_files:%.cpp=$(object_output_path)/%.o)
    object_files := $(object_files:$(touchgfx_middlewares_path)/%.c=$(object_output_path)/$(touchgfx_middlewares_path)/%.o)
    object_files := $(object_files:$(cubemx_middlewares_path)/%.c=$(object_output_path)/$(cubemx_middlewares_path)/%.o)
    object_files := $(object_files:$(libjpeg_source_path)/%.c=$(object_output_path)/$(libjpeg_source_path)/%.o)
    object_files := $(object_files:$(Drivers_path)/%.c=$(object_output_path)/Drivers/%.o)
    object_files := $(object_files:%.c=$(object_output_path)/%.o)

    ハードウェアの変更

    すべてのJPEGパスをインクルード・パスに追加します。

    include_paths := $(library_includes) \
    $(foreach comp, $(all_components), $(comp)/include) \
    $(foreach comp, $(cubemx_components), $(comp)/Inc) \
    $(foreach comp, $(touchgfx_generator_components), $(comp)/generated) \
    $(framework_includes) \
    $(cubemx_middlewares_path) \
    $(touchgfx_middlewares_path) \
    $(touchgfx_generator_components) \
    Utilities/JPEG

    次に、すべてのJPEGソース・ファイルをboard_c_filesに追加します。

    board_c_files := \
    $(Drivers_path)/BSP/STM32H750B-DK/stm32h750b_discovery_bus.c \
    $(Drivers_path)/BSP/STM32H750B-DK/stm32h750b_discovery_qspi.c \
    $(Drivers_path)/BSP/STM32H750B-DK/stm32h750b_discovery_sdram.c \
    $(Drivers_path)/BSP/STM32H750B-DK/stm32h750b_discovery_ts.c \
    $(Drivers_path)/BSP/Components/ft5336/ft5336.c \
    $(Drivers_path)/BSP/Components/ft5336/ft5336_reg.c \
    $(Drivers_path)/BSP/Components/mt25tl01g/mt25tl01g.c \
    $(Drivers_path)/BSP/Components/mt48lc4m32b2/mt48lc4m32b2.c \
    Utilities/JPEG/jpeg_utils.c

    外部メモリへのビデオ・バッファの配置

    開発者がSTM32CubeMXを使用して新しいプロジェクトを作成した場合、作成したプロジェクトに関連付けられたリンカ・スクリプトには、TouchGFXで使用可能な領域は含まれていません。 そのため、開発者が別の場所にバッファを配置するようにリンカ・スクリプトを変更するまで、MJPEGビデオのデコードに使用される特定のバッファはリンカによって内部Flashに配置されます。 こうした変更を行わないと、開発者は内部メモリの使用量増大や、ことによると、フル・スクリーン・ビデオ・デコーディングなど、大きなビデオ・バッファへの対応が不可能になります。

    Tip
    次の設定済みのTBSは、外部メモリからのビデオ・デコーディングに対応しています。
    1. STM32F746-DISCO
    2. STM32F769-DISCO
    3. STM32H750-DK

    JPEGデコーディング専用のRGBバッファの定義は、ビデオ・デコーディングが有効な場合に、TouchGFX Generatorによって生成されます。 この定義には、バッファを配置するセクションをリンカに通知するロケーション・プラグマが付随しています。 リンカがこのメモリ領域をリンカ・スクリプトで検出できない場合は、バッファは内部メモリに配置されます。

    LOCATION_PRAGMA_NOLOAD("Video_RGB_Buffer")
    uint32_t videoRGBBuffer[57600] LOCATION_ATTRIBUTE_NOLOAD("Video_RGB_Buffer");

    次のコンパイラ固有のサブセクションでは、SDRAMへのバッファの配置を実現するために開発者が実行できる変更について説明します。 Video_RGB_Bufferは、ビデオ・デコーディングに使用されるバッファを表しています。 サンプルのリンカ・スクリプトでは、TouchGFXフレームバッファ用にSDRAMのいくらかのスペース(0xC0000000から開始)を確保しています。

    1. EWARM
    2. STM32CubeIDE
    3. MDK-ARM
    Further reading
    Generatorユーザガイドのビデオ・デコーディング用のプロジェクトの設定に関するセクションを参照してください。

    以下のすべての例では、STM32F746G-DISCOボードのSDRAMの開始アドレス(0xC0000000->0xC00FF000)からスペースを確保し、リンカがフレームバッファのデータを上書きするリスクなしに、アプリケーションがアドレス(0xC0000000など)を使用してフレームバッファを参照できます。 各例で、リンカは定義されているSDRAM領域にVideo_RGB_Bufferを配置できます。

    Tip
    直接アドレス指定するのではなく、TouchGFXフレームバッファを割り当てている場合は、リンカ・スクリプトでTouchGFX_FramebufferもSDRAMに配置します。

    EWARM(IAR)

    stm32f746xx_flash.icf
    define symbol __ICFEDIT_region_SDRAM_start__   = 0xC00FF000;
    define symbol __ICFEDIT_region_SDRAM_end__ = 0xC0700FFF;

    define region SDRAM_region = mem:[from __ICFEDIT_region_SDRAM_start__ to __ICFEDIT_region_SDRAM_end__];

    place in SDRAM_region { first section Video_RGB_Buffer };

    リンク設定すると、 EWARM\STM32F746G_DISCO\List\STM32F746G_DISCO.mapには、Video_RGB_Bufferに関する次の配置情報が含まれます。

    STM32F746G_DISCO.map
    Video_RGB_Buffer        zero     0xc00f'f000   0x3'8400  TouchGFXGeneratedHAL.o [2]
    - 0xc013'7400 0x3'8400

    STM32CubeIDE

    STM32F746NGHX_FLASH.ld
    MEMORY
    {
    ...
    SDRAM (xrw) : ORIGIN = 0xC00FF000, LENGTH = 8M
    }

    BufferSection (NOLOAD) :
    {
    *(Video_RGB_Buffer Video_RGB_Buffer.*)
    *(.gnu.linkonce.r.*)
    . = ALIGN(0x4);
    } >SDRAM

    コンパイルすると、STM32CubeIDE\Debug\STM32F746G_DISCO.mapには、Video_RGB_Bufferに関する次の配置情報が含まれます。

    STM32F746G_DISCO.map
    BufferSection   0x00000000c00ff000    0x1c200
    *(Video_RGB_Buffer Video_RGB_Buffer.*)
    Video_RGB_Buffer
    0x00000000c00ff000 0x1c200 Application/User/TouchGFX/target/generated/TouchGFXGeneratedHAL.o
    0x00000000c00ff000 videoRGBBuffer

    MDK-ARM(Keil)

    STM32F746G_DISCO.sct
    LR_IROM1 0x08000000 0x00200000  {    ; load region size_region
    ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
    *.o (RESET, +First)
    *(InRoot$$Sections)
    .ANY (+RO)
    }
    RW_IRAM1 0x20000000 0x00050000 { ; RW data
    .ANY (+RW +ZI)
    }
    RW_SDRAM 0xC00FF000 UNINIT 0xC0700FFF {
    *.o (Video_RGB_Buffer)
    }
    }

    ビデオバッファを保持するセクションにUNINIT属性を必ず含めてください。 これにより、初期化されていないデータとしてメモリ領域が確実に残されます。 リンク設定すると、 MDK-ARM\STM32F746G_DISCO\STM32F746G_DISCO.mapには、Video_RGB_Bufferに関する次の配置情報が含まれます。

    STM32F746G_DISCO.map
    Video_RGB_Buffer                         0xc00ff000   Section    115200  touchgfxgeneratedhal.o(Video_RGB_Buffer)