2024,江端さんの忘備録

ドキュメント72時間SP フランス・パリ 街角のマンガ喫茶で』を視聴しました。

I watched " Document 72 Hours SP: Paris, France - At a Manga Cafe on a Street Corner ".

楽しかったです。

It was fun.

私の知っているアニメやコミックが、海外でも人気があるのは嬉しいです。

I am glad that anime and comics I know are also popular overseas.

二次創作物も好きです。

I also like derivative works.

―― ゴーダマシッダールタさん没後、2500年オーダの時間をかけて創作され続けた膨大な物量の「同人誌」

コンテンツを作成して頂いている原作者の方は言うに及ばず、その編集、翻訳や拡販に努力されている皆様の努力のお陰があってのことかと思います。

I am grateful for the efforts of all those who are editing, translating, and promoting the content, not to mention the original authors who are creating them.

その成果を誇ってもいいのは「上記の方々」であって、「日本」ではありませんが。

It is "the above people" who can be proud of their achievements, though not "Japan.

それはさておき。

Aside from that.

------

ChatGPTに「日本国内のマンガとアニメの市場規模の合計、または、日本を除く海外における日本のマンガやアニメの市場規模の合計をフェルミ推定で概算して下さい」と頼んでみたところ、国内の市場規模は6兆円、海外では4.6兆円と出してきました。

When we asked ChatGPT to estimate the total market size of manga and anime in Japan, or the total market size of Japanese manga and anime overseas excluding Japan, using Fermi estimation, they came up with 6 trillion yen for the domestic market and 4.6 trillion yen for the overseas market.

一方、フェルミ推定ではなく、過去データからの推定を頼んでみたら、日本国内市場規模は3兆6937億円、海外では約1兆4600億円と出てきました。

On the other hand, when we asked for an estimate based on historical data rather than Fermi's estimation, we came up with a market size of 3.6937 trillion yen in Japan and about 1.46 trillion yen overseas.

「韓国国内の韓国ドラマの市場規模の合計、または、韓国を除く海外における韓国ドラマの市場規模の合計をフェルミ推定ではなく、過去のデータに基づいて概算して下さい」とお願いしたところ、こちらは、それぞれ、9兆5715億円(の大部分)、1兆6740億円となりました。

When I asked for a rough estimate of the total market size of Korean dramas in Korea or the total market size of Korean dramas overseas, excluding Korea, based on historical data rather than Fermi estimates, I got 9,571.5 billion yen (most of it) and 1,674.0 billion yen, respectively.

日本国内のマンガとアニメの市場規模と韓国のドラマの市場規模は、拮抗している(やや日本の方が強い?)という値が出てきました。

The market size of the Japanese domestic manga and anime market and the Korean drama market are close (slightly more substantial in Japan?).

------

昔、私は『韓国では、ドラマのコンテンツに国家予算が投入されている』という話を、聞いたような気がします。

I think I heard long ago that the government invested in the budget for drama content in Korea.

比して、日本では、アニメ制作者を、『安価なカカオやコーヒー豆を買い叩き、あるいは、格安の衣服を作らせる第三世界の労働者と同程度の低い地位のままにしている』との話も聞いたことがあります。

In comparison, I have heard that in Japan, animation producers are "left with the same low status as third-world workers who make them forced to buy cheap cacao and coffee beans or make cheap clothes.

上記の話はウラを取っていませんので、私が、誤解していたら大変申し訳ありませんが ――

I have not checked the above story as a fact check, and I am very sorry if I have misinterpreted it, but--

『韓国のドラマと同程度の規模の市場を持つマンガやアニメのコンテンツを、日本国は全く保護していない』

"The Japanese state does not protect manga and anime content, which have a market as large as Korean dramas."

という理解で良いでしょうか?

Am I correct in my understanding that this is the case?

なにしろ、私は、アニメのエンドロールに「提供: 日本国文化庁」とか入っているのを見たことありませんし。

After all, I have never seen "courtesy of the Agency for Cultural Affairs of Japan" in the end roll of an anime.

(この辺について、私に教えてくれる方のご連絡をお待ちしております。謙虚にご講義を受けるつもりです。)

(I look forward to hearing from anyone who can enlighten me on this area. I will humbly accept your lecture.)

------

とは言え、『コンテンツ文化に、国家が関わってくるとロクなことにならない』というのも、また事実ですので ―― 『国策として、何もしない』というのは、それはそれで悪くない、とも思うこともあります。

However, it is also a fact that "when the state gets involved in content culture, it can lead to bad things," - so I sometimes think that "doing nothing as a matter of national policy" is not such a bad idea.

伝統芸能などとは異なり、サブカルについては『国に借りを作っておかない』というのも、ありかなぁ、とも思います。

Unlike traditional arts, I think it is important to "not owe a debt to the government" when it comes to subculture.

ただ、このまま放置しておいて、日本のサブカルが衰退していくようなことになれば、多分、私はとても悲しいです。

However, I will probably be despondent if this is left unchecked and the Japanese subculture is left to decline.

しかしながら、アニメ制作者の酷い現場の現状が続けば、"それ"はいつかは起こるのだろう、とも思います。

However, I believe that "it" will happen someday if the terrible situation of animation producers in the field continues.

------

では、日本の次に、マンガとアニメの覇権を握るとすれば、それはどの国か?

So, after Japan, which country will be most dominant in manga and anime, if any?

中国(大陸)が最右翼ですが、共産党一党独裁をしている内は大丈夫でしょう。権力が、サブカルの表現の自由に敵対するでしょうから。

China (mainland) is the most right-wing, but as long as they have a one-party communist dictatorship, they will be fine. The power will be hostile to the freedom of expression of the subculture.

北米(アメリカ合衆国)は、"自国正義ファースト"の国ですので、こっちも心配ないです。

North America (United States of America) is a "justice first" country, so there is no need to worry here either.

韓国は、ドラマで成功していますので、この国は強いのではないかと。

Korea has been prosperous in dramas, so this country must be strong.

あと台湾なども強そうです(半導体は強いですね)。

Also, Taiwan seems to be strong (semiconductors are strong).

イスラム圏は除外して良さそうです。日本のサブカル持ち込んだら鞭打ちになるかもしれません(酷い偏見です。私、イスラム圏の学友が何人かいます)。

The Muslim world seems to be an excellent place to exclude. If you bring in a Japanese subculture, you may get flogged (I'm prejudiced. I have several Muslim schoolmates).

根拠はないのですが、『欧州の小国のどこかが、突然立ち上がっているんじゃないかな』という予感があります。

I don't have any evidence, but I have a feeling that 'some of the smaller European countries will suddenly be standing up.

-----

ちなみに、「日本のマンガやコンテンツ」の部分を、「自動車産業」に置き換えてみたら、ChatGPTは、それぞれ、57兆円、33兆円と回答しました。

Incidentally, if we replace the "Japanese manga and content" part with the "automobile industry," ChatGPT responded 57 trillion yen and 33 trillion yen, respectively.

「ハードとソフトを比較するのはナンセンス」とは思いつつも、市場規模のケタが違うなぁ、と実感しました。

Although I think it is nonsense to compare hardware and software, I realized that the market scale is very different.

2024,江端さんの技術メモ

これからGO言語で構造体を使い倒さねばならない私(江端)が、これから何度でもハマるような気がするので、わざわざ簡単なプログラムを作って、今後の自分の為にメモを残す。

agentsスライスの要素を変更しても、その変更が反映されない理由として、agent変数が値渡しである可能性があります。Goでは、スライスやマップなどのリファレンスタイプを使わない限り、変数は値渡しされます。

具体的には、以下のようなコードでは、agent変数はスライスagentsの要素をコピーしたものであり、変更はagentsスライス自体には反映されません。

 

重要なポイントは、

"for i, agent := range agents {" は表示するだけなら問題はないが、書き込みはできず、

" for i := range agents {
          agent := &agents[i] // この1行が滅茶苦茶重要"
としないと、書き込みが反映されない、ということであり、変更点は、以下のようにforループ内でagentをポインタとして扱うことである。

 

また表示の際にも、例えば1000番目の構造体のエージェントだけを表示したいのであれば、

i := 1000
	if i < len(agents) {  // これは構造体の数を越えていないかをチェックする
		agent := &agents[i]
この1行が滅茶苦茶重要"
		fmt.Printf("hh_id:%d idv_id:%d\n", agent.hh_id, agent.idv_id)
		fmt.Printf("Agent %d: q1=%d, q2t=%d, q31=%d, q32=%d, q33=%d, q34=%d, q41a=%d, q42a=%d, q43a=%d, q44a=%d, q45a=%d, q46a=%d, q47a=%d, q41e=%d, q42e=%d, q43e=%d, q44e=%d, q45e=%d, q46e=%d, q47e=%d, q10=%d, q13=%d, q14=%d, no_answer=%d\n",
			i, agent.q1, agent.q2t, agent.q31, agent.q32, agent.q33, agent.q34,
			agent.q41a, agent.q42a, agent.q43a, agent.q44a, agent.q45a, agent.q46a, agent.q47a,
			agent.q41e, agent.q42e, agent.q43e, agent.q44e, agent.q45e, agent.q46e, agent.q47e,
			agent.q10, agent.q13, agent.q14, agent.no_answer)

		for _, trip := range agent.trip {
			fmt.Printf("trip: {id:%d act_id:%d trip_id:%d day:%d origin:%s destination:%s ox:%.6f oy:%.6f dx:%.6f dy:%.6f m_ox:%.6f m_oy:%.6f m_dx:%.6f m_dy:%.6f dep_area:%s arr_area:%s dep_time:%s m_dep_time:%s arr_time:%s m_arr_time:%s stay_time:%.2f traffic:%s next_id:%d category:%d}\n",
				trip.id, trip.act_id, trip.trip_id, trip.day, trip.origin, trip.destination, trip.ox, trip.oy, trip.dx, trip.dy, trip.m_ox, trip.m_oy, trip.m_dx, trip.m_dy,
				trip.dep_area, trip.arr_area, trip.dep_time.Format("15:04:05"), trip.m_dep_time.Format("15:04:05"), trip.arr_time.Format("15:04:05"), trip.m_arr_time.Format("15:04:05"), trip.stay_time.Hours(), trip.traffic, trip.next_id, trip.category)
		}

以下は、その考え方を簡易に表現したもの

 

普通の構造体の取扱は、こんな感じでいい。

// G:\home\ebata\tomioka3B\src\others\main85.go

package main

import (
	"errors"
	"fmt"
)

// Trip構造体の定義
type Trip struct {
	id      int
	act_id  int
	trip_id int
	day     int
}

// Agent構造体の定義
type Agent struct {
	hh_id     int
	idv_id    int
	trip      []Trip
	sex       int
	no_answer int
}

// getGenderメソッドの定義
func (a Agent) getGender() (string, error) {
	switch a.sex {
	case 1:
		return "女性", nil
	case 2:
		return "男性", nil
	case 3:
		return "その他(未回答)", nil
	default:
		return "", errors.New("invalid sex value")
	}
}

func main() {
	// エージェントを5個生成
	agents := make([]Agent, 5)
	for i := 0; i < 5; i++ {
		agents[i] = Agent{
			hh_id:  i + 1,
			idv_id: i + 1,
			sex:    (i % 3) + 1, // 1, 2, 3をループ
			trip: []Trip{
				{id: 1, act_id: 10, trip_id: 100 + i, day: 1},
				{id: 2, act_id: 20, trip_id: 200 + i, day: 2},
			},
		}
	}

	// 各エージェントの性別とTrip情報を表示
	for i, agent := range agents {
		gender, err := agent.getGender()
		if err != nil {
			fmt.Printf("Agent %d: Error: %v\n", i+1, err)
		} else {
			fmt.Printf("Agent %d: Gender: %s\n", i+1, gender)
		}
		for _, trip := range agent.trip {
			fmt.Printf("\tTrip ID: %d, Act ID: %d, Trip ID: %d, Day: %d\n", trip.id, trip.act_id, trip.trip_id, trip.day)
		}
	}
}

出力結果
$ go run main85.go
Agent 1: Gender: 女性
Trip ID: 1, Act ID: 10, Trip ID: 100, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 200, Day: 2
Agent 2: Gender: 男性
Trip ID: 1, Act ID: 10, Trip ID: 101, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 201, Day: 2
Agent 3: Gender: その他(未回答)
Trip ID: 1, Act ID: 10, Trip ID: 102, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 202, Day: 2
Agent 4: Gender: 女性
Trip ID: 1, Act ID: 10, Trip ID: 103, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 203, Day: 2
Agent 5: Gender: 男性
Trip ID: 1, Act ID: 10, Trip ID: 104, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 204, Day: 2

このプログラムの後ろに、Agent 4を変更するプログラムを追加したい、とする。

Agent 4は
(1)hh_idを1000, idv_idを1001, sexを2、no_answerを1
(2)
Trip ID: 123, Act ID: 456, Trip ID: 789, Day: 1
Trip ID: 321, Act ID: 654, Trip ID: 987, Day: 2
とするプログラムは以下のようになる。

 

package main

import (
	"errors"
	"fmt"
)

// Trip構造体の定義
type Trip struct {
	id      int
	act_id  int
	trip_id int
	day     int
}

// Agent構造体の定義
type Agent struct {
	hh_id     int
	idv_id    int
	trip      []Trip
	sex       int
	no_answer int
}

// getGenderメソッドの定義
func (a Agent) getGender() (string, error) {
	switch a.sex {
	case 1:
		return "女性", nil
	case 2:
		return "男性", nil
	case 3:
		return "その他(未回答)", nil
	default:
		return "", errors.New("invalid sex value")
	}
}

func main() {
	// エージェントを5個生成
	agents := make([]Agent, 5)
	for i := 0; i < 5; i++ {
		agents[i] = Agent{
			hh_id:  i + 1,
			idv_id: i + 1,
			sex:    (i % 3) + 1, // 1, 2, 3をループ
			trip: []Trip{
				{id: 1, act_id: 10, trip_id: 100 + i, day: 1},
				{id: 2, act_id: 20, trip_id: 200 + i, day: 2},
			},
		}
	}

	// 各エージェントの性別とTrip情報を表示
	for i, agent := range agents {
		gender, err := agent.getGender()
		if err != nil {
			fmt.Printf("Agent %d: Error: %v\n", i+1, err)
		} else {
			fmt.Printf("Agent %d: Gender: %s\n", i+1, gender)
		}
		for _, trip := range agent.trip {
			fmt.Printf("\tTrip ID: %d, Act ID: %d, Trip ID: %d, Day: %d\n", trip.id, trip.act_id, trip.trip_id, trip.day)
		}
	}

	// Agent 4を変更
	agentIndex := 3
	if agentIndex < len(agents) {
		agents[agentIndex] = Agent{ // for i, agent := range agents のagentに上書きしても反映されない
			hh_id:     1000,
			idv_id:    1001,
			sex:       2,
			no_answer: 1,
			trip: []Trip{
				{id: 123, act_id: 456, trip_id: 789, day: 1},
				{id: 321, act_id: 654, trip_id: 987, day: 2},
			},
		}
	}

	// 変更後のエージェント情報を表示
	fmt.Println("\nAfter modification:")
	for i, agent := range agents {
		gender, err := agent.getGender()
		if err != nil {
			fmt.Printf("Agent %d: Error: %v\n", i+1, err)
		} else {
			fmt.Printf("Agent %d: Gender: %s\n", i+1, gender)
		}
		fmt.Printf("Agent %d: hh_id:%d, idv_id:%d, no_answer:%d\n", i+1, agent.hh_id, agent.idv_id, agent.no_answer)
		for _, trip := range agent.trip {
			fmt.Printf("\tTrip ID: %d, Act ID: %d, Trip ID: %d, Day: %d\n", trip.id, trip.act_id, trip.trip_id, trip.day)
		}
	}
}

出力結果
tomoi@DESKTOP-1QS7OI7 MSYS /g/home/ebata/tomioka3B/src/others
$ go run main85.go
Agent 1: Gender: 女性
Trip ID: 1, Act ID: 10, Trip ID: 100, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 200, Day: 2
Agent 2: Gender: 男性
Trip ID: 1, Act ID: 10, Trip ID: 101, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 201, Day: 2
Agent 3: Gender: その他(未回答)
Trip ID: 1, Act ID: 10, Trip ID: 102, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 202, Day: 2
Agent 4: Gender: 女性
Trip ID: 1, Act ID: 10, Trip ID: 103, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 203, Day: 2
Agent 5: Gender: 男性
Trip ID: 1, Act ID: 10, Trip ID: 104, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 204, Day: 2

After modification:
Agent 1: Gender: 女性
Agent 1: hh_id:1, idv_id:1, no_answer:0
Trip ID: 1, Act ID: 10, Trip ID: 100, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 200, Day: 2
Agent 2: Gender: 男性
Agent 2: hh_id:2, idv_id:2, no_answer:0
Trip ID: 1, Act ID: 10, Trip ID: 101, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 201, Day: 2
Agent 3: Gender: その他(未回答)
Agent 3: hh_id:3, idv_id:3, no_answer:0
Trip ID: 1, Act ID: 10, Trip ID: 102, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 202, Day: 2
Agent 4: Gender: 男性
Agent 4: hh_id:1000, idv_id:1001, no_answer:1
Trip ID: 123, Act ID: 456, Trip ID: 789, Day: 1
Trip ID: 321, Act ID: 654, Trip ID: 987, Day: 2
Agent 5: Gender: 男性
Agent 5: hh_id:5, idv_id:5, no_answer:0
Trip ID: 1, Act ID: 10, Trip ID: 104, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 204, Day: 2

2024,江端さんの技術メモ

TC(Traffic Controller)で、帯域5M、パケットロス10%、遅延1000msを セットするコマンドを教えて下さい

# qdiscの設定をクリア
sudo tc qdisc del dev eth0 root

# トークンバケットフィルター (TBF) を使用して帯域幅を制限
sudo tc qdisc add dev eth0 root tbf rate 5mbit burst 10kb latency 50ms

# ネットエミュレーション(netem)を使用して遅延とパケットロスを追加 sudo tc qdisc add dev eth0 parent 1:1 handle 10: netem delay 1000ms loss 10%

TC(Traffic Controller)のコマンドの一つとして使われている"latency"と"delay"の違いについて教えて下さい。

latency

"latency" は、トークンバケットフィルター (TBF) などのキューイングディシプリン(qdisc)で使用されます。ここでの "latency" は、バッファ内のパケットが許可される最大遅延時間を示します。つまり、指定されたバッファサイズ(burst)が満たされている場合に、パケットがそのバッファ内にどれだけ長く滞留できるかを示します。

delay

"delay" は、ネットエミュレーション(netem)で使用され、パケットに対して指定された遅延を追加します。この遅延は、ネットワークの遅延やラグをシミュレートするために使用されます。

まとめ

  • latency: TBF などのキューイングディシプリンにおいて、バッファ内での最大滞留時間を指定します。パケットの滞留時間が指定された latency を超えると、そのパケットはドロップされる可能性があります。バッファ内の滞留時間であり、ネットワーク全体の遅延を反映するものではありません。
  • delay: netem などで使用され、パケットに対して指定された遅延を直接追加します。ネットワーク全体の遅延やラグをシミュレートするために使用されます。

以上

 

2024,江端さんの技術メモ

type agent_od_2018_harugakkai struct {
	id      int
	hh_id   int
	idv_id  int
	act_id  int
	trip_id int
	day     int

	testtest float64

	origin      string // 自宅
	destination string // 病院

	ox float64
	oy float64
	dx float64
	dy float64

	m_ox float64 // ポリゴン境界補正後のox
	m_oy float64 // ポリゴン境界補正後のoy
	m_dx float64 // ポリゴン境界補正後のdx
	m_dy float64 // ポリゴン境界補正後のdy

追加のm_ox、m_oy、m_dx、m_dyが反映されず(というか、vscodeがエラーといってくる)ので、頭を抱えていましたが、どうやら、同じディレクトリにある別プログラムの定義をひっぱってきているようです。

同様に、メソッドも、無関係なプログラムをひっぱってこられて、VSCode上では警告の嵐になります。

ですので、短かいテストプログラムと言えども、面倒くさいですが、別のディレクトリを切って、そこでテストしなければならないようです。(VScodeは文句言うけど、たぶん、コンパイル/ビルドは通ると思います)。

# 実にもったいない時間の消費をしてしまいました。

 

 

2024,江端さんの技術メモ

ポインタと値の操作: item がリスト内の要素をポインタ経由で取得している場合、item を変更しても元のリストの要素が変更されることがありますが、それ以外の場合はそのような自動的な反映は行われません。必要に応じて、&item を使用してポインタ経由でアクセスし、リスト内の要素を直接変更します。

 

スライスと範囲ループの挙動: Go言語では、for range ループで取得した item は元のスライスの要素のコピーです。これにより、item を直接変更しても元のリストの要素に反映されません。そのため、ポインタ経由でアクセスして変更する必要があります。

失敗例

var estimatedStartTime time.Time
			var estimatedMovingTime time.Duration
			var estimatedStayTime time.Duration

			for i, item := range list {

				if i == 0 {
					estimatedStartTime = estimated_Start_Time(data, item.destination) // 出発時刻(リアル時間)
					fmt.Println("i=0のitem.destination:", item.destination)
					fmt.Println("i=0のestimatedStartTime:", estimatedStartTime)
					item.dep_time = estimatedStartTime // 時刻 (記録用)
					fmt.Println("in i=0  item.dep_time:", item.dep_time)
				} else {
					item.dep_time = estimatedStartTime.Add(estimatedMovingTime + estimatedStayTime)
				}

				fmt.Println("===================>", item.dep_time)

				estimatedMovingTime = estimated_Moving_Time(item.ox, item.oy, item.dx, item.dy) // 移動時間(間隔)
				fmt.Println("estimatedMovingTime:", estimatedMovingTime)

				estimatedStayTime = estimated_Stay_Time(data, item.destination) // 滞在時間(間隔)
				fmt.Println("estimatedStayTime:", estimatedStayTime)

				// item.dep_time = estimatedStartTime // 時刻 (記録用)
				item.stay_time = estimatedStayTime // 滞在時間(間隔) (記録用)


					if i+1 < len(list) {
						fmt.Println("in 558", estimatedStartTime, item.dep_time)
						nextItem := &list[i+1]
						nextItem.dep_time = estimatedStartTime.Add(estimatedMovingTime + estimatedStayTime) // 次の出発時刻 = 現在の出発時刻 + 移動時間
						fmt.Println("After nextItem.dep_time:", nextItem.dep_time)
						fmt.Println("in 562", estimatedStartTime, item.dep_time)
					}


				//fmt.Println("in 565", estimatedStartTime, item.dep_time)

			}

			for i, item := range list {
				fmt.Println(i, "item.dep_time:", item.dep_time)
				fmt.Println(i, "item.stay_time:", item.stay_time)
				fmt.Println(i, "item:", item)
				//fmt.Println(i, "item.dep_time:", item.dep_time.Format("2006-01-02 15:04:05"))
			}

成功例

var estimatedStartTime time.Time
		var estimatedMovingTime time.Duration
		var estimatedStayTime time.Duration

		for i := range list {
			if i == 0 {
				estimatedStartTime = estimated_Start_Time(data, list[i].destination)
				fmt.Println("i=0のitem.destination:", list[i].destination)
				fmt.Println("i=0のestimatedStartTime:", estimatedStartTime)
				list[i].dep_time = estimatedStartTime
				fmt.Println("in i=0  item.dep_time:", list[i].dep_time)
			} else {
				// 前のアイテムの出発時刻に移動時間と滞在時間を加えて計算
				list[i].dep_time = list[i-1].dep_time.Add(estimatedMovingTime + estimatedStayTime)
			}

			// 移動時間と滞在時間を計算する
			estimatedMovingTime = estimated_Moving_Time(list[i].ox, list[i].oy, list[i].dx, list[i].dy)
			fmt.Println("estimatedMovingTime:", estimatedMovingTime)

			estimatedStayTime = estimated_Stay_Time(data, list[i].destination)
			fmt.Println("estimatedStayTime:", estimatedStayTime)

			// 滞在時間を記録用に設定する
			list[i].stay_time = estimatedStayTime

			fmt.Println("===================>", list[i].dep_time)
		}

		for i := range list {
			fmt.Println(i, "item.dep_time:", list[i].dep_time)
			fmt.Println(i, "item.stay_time:", list[i].stay_time)
			fmt.Println(i, "item:", list[i])
		}
	}

そんな仕様、知るかーーーー

2024,江端さんの技術メモ

gst-launch-1.0 rtspsrc location=rtsp://cam:Cam12345@192.168.0.10/Src/MediaInput/stream_1 latency=0 ! rtph264depay ! avdec_h264 ! videoconvert ! videoscale ! video/x-raw,width=640,height=360 ! videorate ! video/x-raw,framerate=5/1 ! x264enc bitrate=1700 speed-preset=ultrafast tune=zerolatency key-int-max=1 ! mpegtsmux ! srtserversink uri = \"srt://192.168.101.10:38089\" latency=500
を実施するためだけのプログラムをGO言語で作成してください

package main

import (
	"fmt"
	"os"

	"github.com/go-gst/go-glib/glib"
	"github.com/go-gst/go-gst/gst"
)

func main() {
	fmt.Println("starting.....")

	// gstreamer初期化処理
	gst.Init(&os.Args)

	// メインループ生成
	mainLoop := glib.NewMainLoop(glib.MainContextDefault(), false)

	// パイプラインの要素を生成
	source, _ := gst.NewElement("rtspsrc")
	depay, _ := gst.NewElement("rtph264depay")
	decoder, _ := gst.NewElement("avdec_h264")
	convert, _ := gst.NewElement("videoconvert")
	scale, _ := gst.NewElement("videoscale")
	rate, _ := gst.NewElement("videorate")
	filter1, _ := gst.NewElement("capsfilter")
	filter2, _ := gst.NewElement("capsfilter")
	encorder, _ := gst.NewElement("x264enc")
	mux, _ := gst.NewElement("mpegtsmux")
	sink, _ := gst.NewElement("srtsink")

	// 各要素のプロパティを設定
	source.SetProperty("location", "rtsp://cam:Cam12345@192.168.0.10/Src/MediaInput/stream_1")
	source.SetProperty("latency", 0)
	filter1.SetProperty("caps", gst.NewCapsFromString("video/x-raw,width=640,height=360"))
	filter2.SetProperty("caps", gst.NewCapsFromString("video/x-raw,framerate=5/1"))
	encorder.SetProperty("bitrate", 1700)
	encorder.SetProperty("speed-preset", "ultrafast")
	encorder.SetProperty("tune", "zerolatency")
	encorder.SetProperty("key-int-max", 1)
	sink.SetProperty("uri", "srt://192.168.101.10:38089")
	sink.SetProperty("latency", 500)

	// パイプラインを生成して要素を追加
	pipeline, _ := gst.NewPipeline("video_player")
	pipeline.AddMany(source, depay, decoder, convert, scale, rate, filter1, filter2, encorder, mux, sink)
	gst.ElementLinkMany(depay, decoder, convert, scale, rate, filter1, filter2, encorder, mux, sink)

	// 動的パッドのリンク
	source.Connect("pad-added", func(element *gst.Element, pad *gst.Pad) {
		pad.Link(depay.GetStaticPad("sink"))
	})

	// パイプラインメッセージ読取
	pipeline.GetPipelineBus().AddWatch(func(msg *gst.Message) bool {
		switch msg.Type() {
		case gst.MessageEOS: // end-of-streamを受信したらパイプラインを停止
			pipeline.BlockSetState(gst.StateNull)
			mainLoop.Quit()
		case gst.MessageError: // エラーメッセージはFatalにする
			err := msg.ParseError()
			fmt.Println("ERROR:", err.Error())
			if debug := err.DebugString(); debug != "" {
				fmt.Println("DEBUG:", debug)
			}
			mainLoop.Quit()
		default:
			// 受信メッセージの表示
			fmt.Println(msg)
		}

		return true
	})

	// パイプライン開始
	pipeline.SetState(gst.StatePlaying)

	// メインループ開始
	mainLoop.Run()
}

2024,江端さんの技術メモ

C言語を使えて、GStreamerが使えて、GO言語を使えて、CGOが使える環境を作っています。

(1)Windowsの方のmsys2とGStreamerのパッケージを削除
Windowsの方のC言語、GStreamerはコンフリクトするので削除しますが、GO言語は、別のタスク(大学の方のシミュレータ)があるので、削除できませんでした。
という訳で、MSYS2の環境を、Windowsの方と切り離して運用するという覚悟ができました。

(2)C:の容量が小さいので、G:\の方にパッケージを分離していたのですが、これをやると、全く動かなくなるので、C:\msys2の配下に勝手に作成される、/c/msys64/home/tomoi/の直下でプログラムの作成をすることにしました。

これ、/usr/local/binの配下に/home/ebataを作るような気持ち悪さがあるのですが、今回は稼動が最優先です。

MSYS2のインストール

  1. MSYS2公式サイトからインストーラをダウンロードします。
  2. インストーラを実行し、画面の指示に従ってMSYS2をインストールします。

2. MSYS2の初期設定

  1. MSYS2ターミナルを起動: MSYS2 MSYSショートカットを使用してMSYS2ターミナルを起動します。
  2. パッケージデータベースと基本パッケージの更新: 以下のコマンドを順番に実行して、パッケージデータベースと基本パッケージを更新します。

    sh

    pacman -Syu

    初回のアップデートが完了したら、ターミナルを一度閉じて再起動します。

  3. 再度更新を実行: ターミナルを再起動後、再度以下のコマンドを実行します。

    sh

    pacman -Syu

3. MinGW-w64のインストール

  1. MinGW-w64ツールチェインのインストール: MSYS2 MinGW 64-bitショートカットを使用してMSYS2ターミナルを起動し、以下のコマンドを実行します。

    sh

    pacman -S mingw-w64-x86_64-toolchain

    これにより、GCC、G++、およびその他の開発ツールがインストールされます。

4. 環境変数の設定

MinGW-w64のバイナリにアクセスするために、環境変数PATHを設定します。

  1. ~/.bashrcファイルの編集: MSYS2ターミナルで~/.bashrcファイルを開きます。

    sh

    nano ~/.bashrc
  2. PATHの設定: 以下の行を追加して保存します。

    sh

    export PATH="/mingw64/bin:$PATH"
  3. 設定の反映: 設定を反映させるために、ターミナルを再起動するか、以下のコマンドを実行します。

    sh

    source ~/.bashrc

5. GStreamerのインストール

  1. GStreamerのパッケージのインストール: MSYS2 MinGW 64-bitショートカットを使用してMSYS2ターミナルを起動し、以下のコマンドを実行します。

    sh

    pacman -S mingw-w64-x86_64-gstreamer mingw-w64-x86_64-gst-plugins-base mingw-w64-x86_64-gst-plugins-good mingw-w64-x86_64-gst-plugins-bad mingw-w64-x86_64-gst-plugins-ugly

    pacman -S mingw-w64-x86_64-gstreamer mingw-w64-x86_64-gst-plugins-base mingw-w64-x86_64-gst-plugins-good mingw-w64-x86_64-gst-plugins-bad mingw-w64-x86_64-gst-libav

6. 確認とテスト

  1. GCCの動作確認: GCCが正しくインストールされているか確認します。

    sh

    gcc --version
  2. 簡単なCプログラムの作成とコンパイル: 簡単なCプログラムを作成してコンパイルします。

    sh

    nano test.c

    以下の内容を入力します。

    c

    #include <stdio.h>

    int main() {
    printf("Hello, World!\n");
    return 0;
    }

    ファイルを保存してNanoエディタを閉じた後、コンパイルします。

    sh

    gcc test.c -o test.exe

    コンパイルが成功したら、実行します。

    sh

    ./test.exe
  3. GStreamerの動作確認: GStreamerが正しくインストールされているか確認します。

    sh

    gst-launch-1.0 --version

    簡単なGStreamerパイプラインを実行して動作確認します。

    sh

    gst-launch-1.0 videotestsrc ! autovideosink

とうぜん 、ここまですんなりできた訳ではありませんが、取り敢えず私が思い出せる程度の情報を載せてあります。

-----

https://github.com/go-gst/go-gst

から、/home/tomoi/go/srcで、 git clone https://github.com/go-gst/go-gst をして、/home/tomoi/go/src/go-gst を作って、

に張ってあったプログラムを、main.goでセーブしたのち、

go run main.go videotestsrc ! glimagesink

で、

と、

が、表われることを確認。

なにがどうなっているのかは、サッパリ分からないが、とりあえず、GoからGstreamerが動いたことは確認できた。

以上

なんか、サラっと書くと自分でも腹たつなぁ。10時間以上はかかったんだけどなぁ

2024,江端さんの技術メモ

Windows10に、GStreamerの1.24をインストール(フルインストールを選ぶこと)をしたのですが、定番の、

$ gst-launch-1.0.exe videotestsrc ! autovideosink
Use Windows high-resolution clock, precision: 1 ms
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
Got context from element 'autovideosink0': gst.d3d11.device.handle=context, device=(GstD3D11Device)"
\(GstD3D11Device\)\ d3d11device2", adapter=(uint)0, adapter-luid=(gint64)41376, device-id=(uint)1042
, vendor-id=(uint)32902, hardware=(boolean)true, description=(string)"Intel\(R\)\ HD\ Graphics\ 4600
";
ERROR: from element /GstPipeline:pipeline0/GstAutoVideoSink:autovideosink0/GstD3D11VideoSink:autovid
eosink0-actual-sink-d3d11video: Cannot create converter
Additional debug info:
Failed to prepare d3d11window
ERROR: pipeline doesn't want to preroll.
Setting pipeline to NULL ...
ERROR: from element /GstPipeline:pipeline0/GstVideoTestSrc:videotestsrc0: Internal data stream error
.
Additional debug info:
../libs/gst/base/gstbasesrc.c(3177): gst_base_src_loop (): /GstPipeline:pipeline0/GstVideoTestSrc:vi
deotestsrc0:
streaming stopped, reason error (-5)
ERROR: pipeline doesn't want to preroll.
Freeing pipeline ...

となります。別のWindows BOXでも、先日も経験して、青ざめていました。

結果として、

$ gst-launch-1.0 videotestsrc ! glimagesink

とすれば動きます。

autovideosinkが動かん、っていうのは、結局分かっていませんが、これは困りものです。

以下自分用メモ

-UDP通信の実験

-受信側

-gst-launch-1.0 videotestsrc ! x264enc ! rtph264pay ! udpsink host=192.168.101.10 port=38089
(ローカルの場合、host=127.0.0.1とする.  host=localhost は動かない)

-送信側

-gst-launch-1.0 udpsrc port=38089 caps="application/x-rtp,media=video,encoding-name=H264,payload=96" ! rtph264depay ! h264parse ! avdec_h264 ! videoconvert ! glimagesink

-

-SRT通信の実験

-受信側

-gst-launch-1.0 srtsrc uri="srt://0.0.0.0:38089?mode=listener" keep-listening=true ! tsdemux ! h264parse ! avdec_h264 ! videoconvert ! glimagesink sync=false

-送信側

-gst-launch-1.0 rtspsrc location=rtsp://cam:Cam12345@192.168.0.10/Src/MediaInput/stream_1 latency=0 ! rtph264depay ! avdec_h264 ! videoconvert ! videoscale ! video/x-raw,width=640,height=360 ! videorate ! video/x-raw,framerate=5/1 ! x264enc speed-preset=ultrafast tune=zerolatency key-int-max=1 ! mpegtsmux ! srtserversink uri = \"srt://192.168.101.10:38089\" latency=500

2024,江端さんの技術メモ

dockerは、どのOS環境でも動くを唄っていますが、基本的に、わたしは、どんなパッケージであろうとも、「これ」を信じていません。

とくに時系列方向については、全く信用していません。

ともあれ、ノートPCにtomioka_dbをdocker-compose.ymlで再構築した時、以下の部分の変更が必要でしたので、逐次メモしていきます。

#version: '3.9'
services:
  db:
    build:
      context: .
    environment:
      POSTGRES_PASSWORD: password
      POSTGRES_DB: tomioka_db
    ports:
      - "15432:5432"
    volumes:
      - ./tomioka_db:/tomioka_db
      - db-data:/var/lib/postgresql/data
  osm2pgsql:
    # image: openfirmware/osm2pgsql:latest
    image: osmtw/osm2pgsql:latest  # イメージ名を変更
    environment:
      PG_PORT_5432_TCP_ADDR: db
      PG_PORT_5432_TCP_PORT: 5432
      PG_ENV_OSM_DB: tomioka_db
      PG_ENV_OSM_USER: postgres
      PG_ENV_POSTGRES_PASSWORD: password
    volumes:
      - ./tomioka_db:/tomioka_db
volumes:
  db-data:

 

2024,江端さんの忘備録

私は今でも、Meadow3を使っています。

I still use Meadow3.

Meadow3とは、Windowsに特化したemacsのことです。

Meadow3 is a Windows-specific emacs.

WindowsNT 4.0より前から使っていますが、今も使い続けています。

I have been using it since before Windows NT 4.0 and continue to use it.

なぜか ―― 動くからです。

Why -- because it works.

現在、Windows11上でも動き続けています。

Currently, it continues to run on Windows 11.

vscodeのemacsキーバインドマッピング 諦めました。

-----

動き続けている限り、使わない理由はありません。

There is no reason not to use it as long as it keeps moving.

.emacsをメンテナンスする気力もありませんので、キーバインドも、当時から固定のままです。

I don't have the energy to maintain .emacs, so key bindings have remained fixed since that time.

もはやMeadow3は、私の体の一部といっても過言ではありません。

It is no exaggeration to say that Meadow3 is now a part of my body.

-----

Meadowが、バージョンアップしたWindowsOSで動かなくなった時に、私の中でも何かが終わるような気がしています。

I feel that something will end for me when Meadow stops working with the upgraded Windows OS.

―― と言いながら、次女のPCにMeadow3をインストールして、今、それで、この文章を書いています。

-- but I installed Meadow3 on my second daughter's PC and am now writing this text with it.

あと、次女のノートPCに大量に貼ってあるステッカーが、ちょっとアバンギャルドで、このPCを学会会場に持ち込む勇気が出ませんでした。

Also, the large number of stickers on my second daughter's laptop was a bit avant-garde, and I could not find the courage to bring this computer to the conference venue.

という訳で、こんなの購入して、ノートPCに貼りつけていました。

So I bought one like this and stuck it on my laptop.

返却時に、元に戻して返すつもりですが。

I intend to return it to its original state when I return it.