211 lines
6.9 KiB
Ruby
211 lines
6.9 KiB
Ruby
# Copyright (c) 2018(-2023) STMicroelectronics.
|
|
# All rights reserved.
|
|
#
|
|
# This file is part of the TouchGFX 4.21.2 distribution.
|
|
#
|
|
# This software is licensed under terms that can be found in the LICENSE file in
|
|
# the root directory of this software component.
|
|
# If no LICENSE file comes with this software, it is provided AS-IS.
|
|
#
|
|
###############################################################################/
|
|
require 'fileutils'
|
|
|
|
def root_dir
|
|
# Get the dirname of this (videoconvert.rb) file:
|
|
@root_dir ||= File.dirname(__FILE__)
|
|
end
|
|
|
|
class Main
|
|
def self.banner
|
|
<<-BANNER
|
|
Convert video files.
|
|
|
|
Usage: #{File.basename($0)} {root_folder} asset_folder generated_folder
|
|
|
|
Example: #{File.basename($0)} assets/videos generated/videos
|
|
will process files in assets/videos and place the result in generated/videos
|
|
|
|
Example: #{File.basename($0)} /c/Project assets/videos generated/videos
|
|
will process files in /c/Project/assets/videos and place the result in /c/Project/generated/videos
|
|
BANNER
|
|
end
|
|
|
|
def self.write_file(file_name, content)
|
|
FileUtils.mkdir_p(File.dirname(file_name))
|
|
unless File.exist?(file_name) && content == File.open(file_name, 'r') { |f| f.read() }
|
|
puts "Generating #{file_name}"
|
|
File.open(file_name, 'w') { |f| f.write(content) }
|
|
end
|
|
end
|
|
|
|
|
|
def self.bin_to_obj(bin, out_dir)
|
|
|
|
symbol_file_name = "#{out_dir}/obj/rename_symbols.txt"
|
|
bin_file_name = File.basename(bin)
|
|
|
|
puts "Generating elf32 object from binary file #{out_dir}/bin/#{bin_file_name}..."
|
|
`arm-none-eabi-objcopy.exe -B arm --rename-section .data=ExtFlashSection,contents,alloc,load,readonly,data -I binary -O elf32-littlearm \"#{out_dir}/bin/#{bin_file_name}\" \"#{out_dir}/obj/#{bin_file_name}.o\"`
|
|
|
|
#Rename the symbols
|
|
output_folder_name_subst = "#{out_dir+'/bin'}".gsub('.', '_').gsub('/', '_')
|
|
bin_file_name_subst = File.basename(bin).gsub('.', '_').gsub('/', '_')
|
|
str = output_folder_name_subst + "_" + bin_file_name_subst
|
|
|
|
content =
|
|
"_binary_#{str}_start video_#{bin_file_name_subst}_start\n" +
|
|
"_binary_#{str}_end video_#{bin_file_name_subst}_end\n" +
|
|
"_binary_#{str}_size video_#{bin_file_name_subst}_size\n"
|
|
|
|
puts "Renaming symbols..."
|
|
File.open(symbol_file_name, 'w') { |f| f.write(content) }
|
|
|
|
# Bulk rename using objcopy --redefine-syms
|
|
`arm-none-eabi-objcopy.exe --redefine-syms #{symbol_file_name} \"#{out_dir}/obj/#{bin_file_name}.o\"`
|
|
|
|
#Remove temp file
|
|
FileUtils.rm(symbol_file_name)
|
|
end
|
|
|
|
root_dir = '.'
|
|
if ARGV.count == 3
|
|
root_dir = ARGV.shift
|
|
end
|
|
|
|
if ARGV.count != 2
|
|
abort self.banner
|
|
end
|
|
|
|
Dir.chdir(root_dir) do
|
|
avi_dir = ARGV.shift.gsub('\\', '/')
|
|
out_dir = ARGV.shift.gsub('\\', '/')
|
|
bin_dir = File.join(out_dir, 'bin')
|
|
obj_dir = File.join(out_dir, 'obj')
|
|
avis = Dir[File.join(avi_dir, '**', '*.avi')]
|
|
|
|
# Create the output folder:
|
|
FileUtils.mkdir_p(bin_dir)
|
|
|
|
# Create mapping from existing .avi files to the .bin files
|
|
avi2bin = {}
|
|
avi2obj = {}
|
|
obj2avi = {}
|
|
bin2avi = {}
|
|
|
|
avis.each do |avi|
|
|
bin = File.join(bin_dir, File.basename(avi.gsub(/avi$/i,'bin')))
|
|
obj = File.join(obj_dir, File.basename(avi.gsub(/avi$/i,'bin.o')))
|
|
avi2bin[avi] = bin
|
|
avi2obj[avi] = obj
|
|
|
|
if bin2avi[bin]
|
|
abort "Duplication avi files: #{bin2avi[bin]} and #{avi}"
|
|
end
|
|
|
|
bin2avi[bin] = avi
|
|
obj2avi[obj] = avi
|
|
end
|
|
|
|
# Remove bin files that have no corresponding avi file
|
|
Dir[File.join(bin_dir, '*.bin')].each do |bin|
|
|
if !bin2avi[bin]
|
|
puts "Removing #{bin}"
|
|
FileUtils.rm_f(bin)
|
|
end
|
|
end
|
|
|
|
# Remove obj files that have no corresponding avi file
|
|
Dir[File.join(obj_dir, '*.bin.o')].each do |obj|
|
|
if !obj2avi[obj]
|
|
puts "Removing #{obj}"
|
|
FileUtils.rm_f(obj)
|
|
end
|
|
end
|
|
|
|
# Now process each avi file
|
|
avi2bin.each do |avi,bin|
|
|
if !File.exist?(bin) || (File.mtime(avi) > File.mtime(bin))
|
|
puts "Generating #{bin}"
|
|
FileUtils.cp(avi, bin)
|
|
end
|
|
end
|
|
|
|
# Convert .bin to .obj
|
|
FileUtils.mkdir_p("#{out_dir}/obj")
|
|
avi2obj.each do |avi, obj|
|
|
bin = avi2bin[avi]
|
|
|
|
if !File.exist?(obj) || (File.mtime(bin) > File.mtime(obj))
|
|
puts "Converting #{bin} to #{obj}"
|
|
bin_to_obj(bin, out_dir)
|
|
end
|
|
end
|
|
|
|
# Generate header file
|
|
hpp_content = ""
|
|
keil_export = ""
|
|
keil_incbin = ""
|
|
|
|
avi2bin.each do |avi,bin|
|
|
name = File.basename(bin).gsub('.', '_').gsub('/', '_')
|
|
length = File.size(avi);
|
|
|
|
symbol = "video_#{name}"
|
|
start_symbol = "#{symbol}_start"
|
|
length_symbol = "#{symbol}_length"
|
|
|
|
hpp_content += "const uint32_t #{length_symbol} = #{length};\n"
|
|
hpp_content += "#ifdef SIMULATOR\n"
|
|
hpp_content += "extern const uint8_t* #{start_symbol};\n"
|
|
hpp_content += "#else\n"
|
|
hpp_content += "extern const uint8_t #{start_symbol}[];\n"
|
|
hpp_content += "#endif\n\n"
|
|
|
|
keil_export += "\tEXPORT\t#{start_symbol}\n"
|
|
keil_incbin += "\n#{start_symbol}\n\tINCBIN\t../TouchGFX/#{bin}\n"
|
|
end
|
|
|
|
hpp_file = File.join(out_dir, 'include', 'videos', 'VideoDatabase.hpp')
|
|
write_file(hpp_file,
|
|
"// Generated by videoconvert. Please, do not edit!\n\n"+
|
|
"#ifndef TOUCHGFX_VIDEODATABASE_HPP\n"+
|
|
"#define TOUCHGFX_VIDEODATABASE_HPP\n"+
|
|
"\n#include <touchgfx/hal/Types.hpp>\n\n"+
|
|
hpp_content+
|
|
"#endif // TOUCHGFX_VIDEODATABASE_HPP\n")
|
|
|
|
project_file = Dir['../*.ioc'].first
|
|
toolchain_is_keil = false # Assume it is not Keil
|
|
if project_file
|
|
# From cubemx_project_selector.rb in touchgfx-cli:
|
|
content = File.read(project_file, :encoding=>'utf-8')
|
|
target_toolchain = content.match(/ProjectManager.TargetToolchain=([\w\s\d\.\-]+)/) || abort("Unable to parse #{File.expand_path(@project_file)}")
|
|
toolchain = target_toolchain.captures.first
|
|
toolchain_is_keil = toolchain.match(/MDK-ARM/) # "ProjectManager.TargetToolchain=MDK-ARM..." is Keil
|
|
end
|
|
|
|
keil_path = [out_dir, 'src', 'keil', 'Videos.s']
|
|
keil_file = File.join(keil_path)
|
|
# Only generate Videos.s if there are video files AND we are using Keil:
|
|
if avi2bin.empty? || !toolchain_is_keil
|
|
# Try to remove existing Videos.s file and folder structure (if it is empty)
|
|
begin
|
|
FileUtils.rm(keil_file) if File.exist?(keil_file)
|
|
keil_folder = File.join(keil_path[0...-1])
|
|
FileUtils.rmdir(keil_folder) if File.directory?(keil_folder)
|
|
src_folder = File.join(keil_path[0...-2])
|
|
FileUtils.rmdir(File.join(keil_path[0...-2])) if File.directory?(src_folder);
|
|
rescue
|
|
end
|
|
else
|
|
# There are videos and we are on Keil. Generate Videos.s
|
|
write_file(keil_file,
|
|
"; Generated by videoconvert. Please, do not edit!\n\n"+
|
|
"\tAREA\tExtFlashSection, DATA, READONLY\n\n"+
|
|
keil_export+
|
|
keil_incbin+
|
|
"\n\tEND\n")
|
|
end
|
|
end
|
|
end
|