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

ビデオ・デコーディング

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

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

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

シングル・フレームバッファ(アドレスによる指定)

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

この記事のすべてのセクションを読んでから、次に進んでください。

Tip
STM32H750-DK、STM32F769-DISCOおよびSTM32F746G-DISCO TouchGFX Board Setup(TBS)の最新バージョンでは、STM32CubeMX設定によるソフトウェアとJPEGハードウェアの両方のデコーディングに対応しています。

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

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

TouchGFX Software Decoderでは、LibJPEGでデコードされるデータのピクセル順序をBGRにする必要があります。 この設定がRGBのままの場合は、R色成分とB色成分がアプリケーション内でスワップされます。 さらに、各ピクセルのサイズは3バイトにする必要があります(4バイトの場合は、ビデオがXRGBフォーマットでエンコードされていることを意味します)。

Caution
RGB_ORDERINGの設定をBGRに設定し、ピクセル・サイズを3(24ビット)にします。

LibJPEGの設定

STM32CubeMXからLibJPEGを有効にすると、TouchGFX Generatorユーザガイドに記載されているように、ソフトウェア・デコーディングをTouchGFX Generatorから有効にできるようになります。

TouchGFX Generator: ビデオ・デコーディング

RTOSのサポート

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

ビデオ・タスク・スタック・サイズ(CMSIS V2の場合はワード数で定義)とRTOSヒープ・サイズは2つの重要な要素です。LibJPEGでソフトウェア・デコーディングするために、RTOSヒープ・サイズは動的なメモリ割り当てを使用します。 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)

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

ビデオ・データ

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に関するセクションを参照してください。

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

TouchGFX Generatorユーザガイドに記載されているように、ハードウェア・デコーディングを可能にするために、JPEG IPをSTM32CubeMXで有効にする必要があります。 ソフトウェア・デコーディングとハードウェア・デコーディングはいくつかの特徴を共有しています。また、違いについては、このセクションで説明します。

RTOSのサポート

メモリを動的に割り当てるソフトウェア・スタックがないため、FreeRTOSスタック・サイズはソフトウェア・デコーディングの場合よりも大幅に小さくすることができます。 プロジェクトのその他のタスクに対応できるほどのサイズを維持してください。

STM32F769-DISCO

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

JPEGのパラメータ設定

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

JPEG 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の設定

Caution
H7については、*ユーザ・コード*を追加して、データ送受信に対するDMAリクエストを適切に設定する必要があります。

STM32CubeMXからSTM32H750などのコードを生成する場合は、残念ながら、MDMAハンドラにMDMAを設定するためのコード(上記で定義)が欠落しているため、開発者はハイライト表示されているユーザ・コードを手動で追加する必要があります。

Core\Src\stm32h7xx_hal_msp.c
void HAL_JPEG_MspInit(JPEG_HandleTypeDef* hjpeg)
{
if(hjpeg->Instance==JPEG)
{
/* USER CODE BEGIN JPEG_MspInit 0 */
hmdma_jpeg_infifo_th.Init.Request = MDMA_REQUEST_JPEG_INFIFO_TH;
hmdma_jpeg_outfifo_th.Init.Request = MDMA_REQUEST_JPEG_OUTFIFO_TH;
/* USER CODE END JPEG_MspInit 0 */
...

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を移行してビデオ・デコーディングに対応

利用可能になる前に、ビデオ・デコーディングに対応したボードの1つのTBSから作成したプロジェクトを移行し、そのプロジェクトでTouchGFX Designerの[Run Target]を使用できるようにしたい場合は、GCC Makefileにいくつかの変更を手動で加える必要があります。 必要な変更の概要およびその変更が必要な理由については、後続のセクションで説明します。 変更により、以前の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

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

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

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

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

LOCATION_PRAGMA("Video_RGB_Buffer")
uint32_t videoRGBBuffer[57600] LOCATION_ATTRIBUTE("Video_RGB_Buffer");

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

  1. EWARM
  2. STM32CubeIDE
  3. MDK-ARM
Further reading
TouchGFX 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 :
{
*(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 0xC0700FFF {
*.o (Video_RGB_Buffer)
}
}

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

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