クラッキングでぶっ壊されてしまったニコニコ動画が復活し、シン・ニコニコ動画になって帰ってきました。いちユーザーとしては嬉しい気分でいっぱいです。
しかし前と比べて困ったことが起きていて、BizHawkで出力した動画をシン・ニコニコ動画にアップロードしようとすると「この動画の映像形式には対応していません」とエラーが出てしまって投稿できません。試行錯誤の末、解決方法を見つけたのでメモしておきます。
端的に言えば原因はピクセルフォーマットでした。BizHawkは特に何も言わないとYUV444で出力しますが、ニコニコ動画はYUV420でないと受け付けてくれないようです。どこにもそんな制約は書いていないため、仕様か?バグか?どちらともわかりません。
YUV420にする方法ですけども、BizHawkの出力設定を[Custom]にして、下記のようにピクセルフォーマットを明示的に指定すればYUV420で出力してくれました。
-c:a aac -c:v libx264 -preset ultrafast -pix_fmt yuv420p -f mp4
もしすでにYUV444で出力済みの動画ならば、ffmpegを使って再エンコードすれば良いです。
$ ffmpeg -i input.mp4 \
-vcodec libx264 -vb 2048000 -r 60 -s 1280x720 -pix_fmt yuv420p \
-acodec aac -ar 44100 -ab 192000 output.mp4
動画ビットレート(-vb)、フレームレート(-r)、動画サイズ(-s)は元の動画に応じて調整してください。
この記事にコメントする
目次: Linux
以前、OpenSBIがRISC-V CPUの拡張機能をどのように認識し有効にするか調べました。今回はどのようにCPUの数を認識するか調べます。OpenSBIのプラットフォームは今まで同様にgenericを使います。
実はそんなに難しくなく、デバイスツリーの/cpuノードを読みに行くだけのようです。/cpuノードの例としてQEMU virtマシン、4CPUで起動したときにQEMUが生成するデバイスツリーを下記に示します。長いのでCPU_2, 3は省略しています。名前やラベル、regが2や3になるだけです。
/ {
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <10000000>;
cpu0: cpu@0 {
compatible = "riscv";
reg = <0>;
device_type = "cpu";
riscv,cbop-block-size = <64>;
riscv,cboz-block-size = <64>;
riscv,cbom-block-size = <64>;
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "h",
"zic64b", "zicbom", "zicbop", "zicboz",
"ziccamoa", "ziccif", "zicclsm", "ziccrse",
"zicntr", "zicsr", "zifencei", "zihintntl",
"zihintpause", "zihpm", "za64rs", "zawrs",
"zfa", "zca", "zcd", "zba", "zbb", "zbc", "zbs",
"ssccptr", "sscounterenw", "sstc", "sstvala",
"sstvecd", "svadu";
riscv,isa-base = "rv64i";
riscv,isa = "rv64imafdch_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_zicntr_zicsr_zifencei_zihintntl_zihintpause_zihpm_za64rs_zawrs_zfa_zca_zcd_zba_zbb_zbc_zbs_ssccptr_sscounterenw_sstc_sstvala_sstvecd_svadu";
mmu-type = "riscv,sv57";
status = "okay";
cpu0_intc: interrupt-controller {
compatible = "riscv,cpu-intc";
interrupt-controller;
#interrupt-cells = <1>;
};
};
cpu1: cpu@1 {
compatible = "riscv";
reg = <1>;
device_type = "cpu";
riscv,cbop-block-size = <64>;
riscv,cboz-block-size = <64>;
riscv,cbom-block-size = <64>;
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "h",
"zic64b", "zicbom", "zicbop", "zicboz",
"ziccamoa", "ziccif", "zicclsm", "ziccrse",
"zicntr", "zicsr", "zifencei", "zihintntl",
"zihintpause", "zihpm", "za64rs", "zawrs",
"zfa", "zca", "zcd", "zba", "zbb", "zbc", "zbs",
"ssccptr", "sscounterenw", "sstc", "sstvala",
"sstvecd", "svadu";
riscv,isa-base = "rv64i";
riscv,isa = "rv64imafdch_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_zicntr_zicsr_zifencei_zihintntl_zihintpause_zihpm_za64rs_zawrs_zfa_zca_zcd_zba_zbb_zbc_zbs_ssccptr_sscounterenw_sstc_sstvala_sstvecd_svadu";
mmu-type = "riscv,sv57";
status = "okay";
cpu1_intc: interrupt-controller {
compatible = "riscv,cpu-intc";
interrupt-controller;
#interrupt-cells = <1>;
};
};
cpu2: cpu@2 {
/* 省略 */
};
cpu3: cpu@3 {
/* 省略 */
};
OpenSBIがCPU数を確認するコードは下記のようになっています。
// opensbi/platform/generic/platform.c
unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1,
unsigned long arg2, unsigned long arg3,
unsigned long arg4)
{
const char *model;
void *fdt = (void *)arg1; //★★デバイスツリーのアドレス、レジスタa1を使ってOpenSBIに渡す★★
u32 hartid, hart_count = 0;
int rc, root_offset, cpus_offset, cpu_offset, len;
//...
cpus_offset = fdt_path_offset(fdt, "/cpus");
if (cpus_offset < 0)
goto fail;
fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
//★★device_typeがcpu、regプロパティに値が入っていれば、CPUのノードとみなす★★
rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
if (rc)
continue;
if (SBI_HARTMASK_MAX_BITS <= hartid)
continue;
//★★statusプロパティがokかokayなら有効なCPUとみなす★★
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
//★★ハート数を1つ増やす★★
//★★hartidは連番とは限らないため、hartindexとhartidの対応表を作る★★
generic_hart_index2id[hart_count++] = hartid;
}
//★★platform領域に記録する★★
platform.hart_count = hart_count;
platform.heap_size = fw_platform_calculate_heap_size(hart_count);
platform_has_mlevel_imsic = fdt_check_imsic_mlevel(fdt);
デバイスツリー(正確にはFDT: flattened device tree)の/cpuノードを見て、子ノードがCPUの定義であり、有効ならばhart_countを+1するシンプルなコードです。hartidは連番とは限らないため、hartindex(0からCPU数 - 1までの連番)とhartidの対応表generic_hart_index2id[]も同時に作ります。
無効なCPUの扱いも見ておきます。先程のコードからわかる通りstatus = "disabled"つまり無効なCPUの場合は、hartindexとhartidの対応表(platform.hart_index2id[])にhartidが載りません。例としてQEMUにてCPU 4つで起動し、デバイスツリーでCPU 2だけstatus = "disabled"にしたときのhartindexとhartidの対応表をダンプします。
(gdb) p platform
$11 = {opensbi_version = 65541, platform_version = 1,
name = "riscv-virtio,qemo", '\000' <repeats 46 times>, features = 2,
hart_count = 3, hart_stack_size = 8192, heap_size = 39936, reserved = 0,
platform_ops_addr = 2148010200, firmware_context = 0,
hart_index2id = 0x80083700 <generic_hart_index2id>}
(gdb) p generic_hart_index2id
$15 = {0, 1, 3, 0 <repeats 125 times>}
全CPUが有効ならば0, 1, 2, 3となりますが、CPU 2が無効なので0, 1, 3となっていることがわかります。
次にメインCPUがサブCPUを起こしに行くコードを見ます。アセンブラなので若干分かりづらいですが、hartindexとhartidの対応表に自CPUのhartidが登録されていればCPUを起動し、登録されていない場合はCPUを起動しません。
// opensbi/firmware/fw_base.S
_fdt_reloc_done:
//★★メインCPUはこちら★★
//★★初期化処理が終わるとここに到達する★★
//★★_boot_statusにBOOT_STATUS_BOOT_HART_DONEを書き込むとサブCPU側がループを抜ける★★
/* mark boot hart done */
li t0, BOOT_STATUS_BOOT_HART_DONE
lla t1, _boot_status
fence rw, rw
REG_S t0, 0(t1)
j _start_warm
//★★サブCPUはこちら★★
//★★_boot_statusを読みながらループで待っている★★
/* waiting for boot hart to be done (_boot_status == 2) */
_wait_for_boot_hart:
li t0, BOOT_STATUS_BOOT_HART_DONE
lla t1, _boot_status
REG_L t1, 0(t1)
/* Reduce the bus traffic so that boot hart may proceed faster */
div t2, t2, zero
div t2, t2, zero
div t2, t2, zero
bne t0, t1, _wait_for_boot_hart
_start_warm:
/* Reset all registers except ra, a0, a1, a2, a3 and a4 for non-boot HART */
li ra, 0
call _reset_regs
/* Disable all interrupts */
csrw CSR_MIE, zero
//★★platform.hart_index2idを見て、hartidと一致する要素があるか確かめる★★
/* Find HART count and HART stack size */
lla a4, platform
#if __riscv_xlen > 32
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
#else
lw s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lw s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
#endif
//★★s9はplatform.hart_index2id[0]のアドレス★★
REG_L s9, SBI_PLATFORM_HART_INDEX2ID_OFFSET(a4)
/* Find HART id */
csrr s6, CSR_MHARTID
//★★platform.hart_index2idがNULLだったら処理を止める★★
/* Find HART index */
beqz s9, 3f
li a4, 0
//★★a4 = hartindex
//★★a5 = platform.hart_index2id[hartindex]の値(hartindexに対応するhartid)
//★★s6 = CPUのhartid
//★★s7 = hart数
//★★s9 = platform.hart_index2id[hartindex]のアドレス
1:
#if __riscv_xlen > 32
lwu a5, (s9)
#else
lw a5, (s9)
#endif
//★★hartidとplatform.hart_index2id[n]が一致していたら、ループを抜ける★★
beq a5, s6, 2f
//★★s9を進めて、platform.hart_index2id[0], [1], [2], ...を順に調べる★★
add s9, s9, 4
add a4, a4, 1
blt a4, s7, 1b
//★★s6 = hartindex
2: add s6, a4, zero
//★★hartindexがhart数を超えているか?
//★★ 超える : CPUが無効である、サブCPUを起動しない -> _start_hangへ
//★★ 超えない: CPUが有効である、サブCPUを起動する -> ブランチ命令の先へ
3: bge s6, s7, _start_hang
//...
OpenSBIのロゴが出たあたりでブレークして各スレッドの実行している関数名を見ると、下記のようになります。
(gdb) info thr
Id Target Id Frame
1 Thread 1.1 (CPU#0 [halted ]) sbi_hsm_hart_wait (scratch=0x8008c000, hartid=0)
at opensbi/lib/sbi/sbi_hsm.c:177
2 Thread 1.2 (CPU#1 [running]) 0x0000000080020ffe in fdt32_to_cpu (x=50331648)
at opensbi/lib/utils/libfdt/libfdt_env.h:57
* 3 Thread 1.3 (CPU#2 [halted ]) _start_hang ()
at opensbi/firmware/fw_base.S:409
4 Thread 1.4 (CPU#3 [halted ]) sbi_hsm_hart_wait (scratch=0x80088000, hartid=3)
at opensbi/lib/sbi/sbi_hsm.c:177
Thread Id 3つまりCPU 2(※)だけ_start_hang()に居ることがわかりますね。
(※)GDBのThread Idは1スタートなのでThread Id 1, 2, 3, 4がCPU 0, 1, 2, 3に相当します。
この記事にコメントする
目次: Java
目次: 一覧の一覧
この記事にコメントする
目次: Yocto
Yoctoは特に何も指定せずにビルドすると全スレッドを使おうとします。この挙動はコンパイルだけでなくFetchでも同様のようです。最近のCPUは一般向けでも8〜16スレッドが珍しくないので、何も考えずにbitbakeを実行すると16接続同時にFetchを試みて、サーバー側の同時接続数制限か何かに引っかかってエラーで落ちます。
このエラーが鬱陶しくて困っていたのですが、並列数を2〜4程度(サーバーに蹴られない接続数)に制限して、最初にFetchだけ実行してしまうとよさそうです。
BB_NUMBER_THREADS=2 bitbake core-image-sato --runall=fetch
一度Fetchが終わればその後はFetchしませんから、並列数を16でも32でも好きな数にして良いです。
この記事にコメントする
| < | 2024 | > | ||||
| << | < | 09 | > | >> | ||
| 日 | 月 | 火 | 水 | 木 | 金 | 土 |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
| 29 | 30 | - | - | - | - | - |
25年10月6日
25年10月6日
25年9月29日
25年9月29日
20年8月24日
20年8月24日
16年2月14日
16年2月14日
25年7月20日
25年7月20日
25年7月20日
25年7月20日
25年7月20日
25年7月20日
20年8月16日
20年8月16日
20年8月16日
20年8月16日
24年6月17日
24年6月17日
wiki
Linux JM
Java API
2002年
2003年
2004年
2005年
2006年
2007年
2008年
2009年
2010年
2011年
2012年
2013年
2014年
2015年
2016年
2017年
2018年
2019年
2020年
2021年
2022年
2023年
2024年
2025年
過去日記について
アクセス統計
サーバ一覧
サイトの情報合計:
本日: