ビデオ・デコーディング
このセクションでは、ビデオ・デコーディング機能を備えたTouchGFX HALを生成するためのTouchGFX Generatorの設定方法について説明します。
次のシナリオでは、ソフトウェア(LibJPEG)またはハードウェア(JPEG)のいずれかを使用してTouchGFX HALでビデオ・デコーディングをサポートできるようにする方法について詳しく説明します。 このシナリオでは、STM32F7とSTM32H7の両方について説明します。ハードウェア(JPEG)デコーディングをサポートするためのSTM32CubeMXの設定がSTM32F7では若干異なるからです。
通常、LibJPEG設定とJPEG設定は、STM32CubeMXの[Middleware]および[Multimedia]カテゴリに含まれています。
このシナリオを読む前に、TouchGFXでのMJPEGビデオの使用に関するドキュメントおよびビデオ・ウィジェット自体に関するドキュメントに目を通してください。
この記事のすべてのセクションを読んでから、次に進んでください。
Tip
ソフトウェア・デコーディング
ソフトウェア・デコーディング・ソリューションでは、TouchGFX Generatorユーザガイドで定められているように、LibJPEGミドルウェアをSTM32CubeMXから有効化できる必要があります。 ソフトウェア・デコーディングの設定は、すべてのLibJPEG対応マイクロコントローラ(STM32F4、STM32F7、STM32H7)で同じです。
TouchGFX Software Decoderでは、LibJPEGでデコードされるデータのピクセル順序をBGRにする必要があります。 この設定がRGBのままの場合は、R色成分とB色成分がアプリケーション内でスワップされます。 さらに、各ピクセルのサイズは3バイトにする必要があります(4バイトの場合は、ビデオがXRGBフォーマットでエンコードされていることを意味します)。
Caution
STM32CubeMXからLibJPEGを有効にすると、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
に対して十分な大きさがある必要があります。
上記の設定に基づいて、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
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
)に従う必要があります。
[DMA Settings]から、DMAを使用して、データをJPEGペリフェラルに(メモリからペリフェラル)またはJPEGペリフェラルから(ペリフェラルからメモリ)送信します。 IN
やOUT
に対するDMAリクエストを追加すると、方向パラメータが自動的に設定されます。
これでJPEG対応STM32F7(STM32F769など)に対するハードウェア・デコーディング用のTouchGFX HALの設定は終了です。 STM32CubeMXからコードを生成した後、Designerのビデオ・ウィジェットを使用すると、アプリケーションでJPEGペリフェラルを使用してビデオをデコードできるようになります。
Caution
STM32H750-DK
たとえば、STM32H750とSTM32F769のハードウェア・デコーディング(JPEG対応)の違いは、STM32CubeMXでのDMA転送の設定方法だけです。 UIだけでなく、DMAコンセプトも異なります。
STM32H750の場合、JPEGペリフェラルは、通常のDMAペリフェラルではなくMDMAペリフェラルを使用するようにのみ設定できます。 下の画像に示すように、入出力両方のFIFOしきい値信号のMDMA設定を追加します。
Note
Caution
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
- STM32F746-DISCO
- STM32F769-DISCO
- 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
から開始)を確保しています。
- EWARM
- STM32CubeIDE
- MDK-ARM
Further reading
以下のすべての例では、STM32F746G-DISCOボードのSDRAMの開始アドレス(0xC0000000
->0xC00FF000
)からスペースを確保し、リンカがフレームバッファのデータを上書きするリスクなしに、アプリケーションがアドレス(0xC0000000
など)を使用してフレームバッファを参照できます。 各例で、リンカは定義されているSDRAM領域にVideo_RGB_Buffer
を配置できます。
Tip
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)