From fd90b7209bf15ffd6fce51eebf8a17fbf229d4b5 Mon Sep 17 00:00:00 2001 From: Takeru Ohta Date: Fri, 6 Dec 2024 14:46:40 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=E3=82=B3=E3=83=BC=E3=83=87=E3=83=83?= =?UTF-8?q?=E3=82=AF=E5=90=8D=E9=83=A8=E5=88=86=E3=81=AF=E3=81=84=E3=81=A3?= =?UTF-8?q?=E3=81=9F=E3=82=93=E6=B1=BA=E3=82=81=E3=81=86=E3=81=A1=E3=81=A7?= =?UTF-8?q?=20H.265=20=E5=AF=BE=E5=BF=9C=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/mp4-media-stream/wasm/src/mp4.rs | 25 ++++++++++++++++++-- packages/mp4-media-stream/wasm/src/player.rs | 4 ++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/mp4-media-stream/wasm/src/mp4.rs b/packages/mp4-media-stream/wasm/src/mp4.rs index 9867d3dd..58663de5 100644 --- a/packages/mp4-media-stream/wasm/src/mp4.rs +++ b/packages/mp4-media-stream/wasm/src/mp4.rs @@ -5,8 +5,8 @@ use serde::Serialize; use shiguredo_mp4::{ aux::SampleTableAccessor, boxes::{ - Av01Box, Avc1Box, FtypBox, HdlrBox, IgnoredBox, MoovBox, Mp4aBox, OpusBox, SampleEntry, - StblBox, TrakBox, Vp08Box, Vp09Box, + Av01Box, Avc1Box, FtypBox, HdlrBox, Hev1Box, IgnoredBox, MoovBox, Mp4aBox, OpusBox, + SampleEntry, StblBox, TrakBox, Vp08Box, Vp09Box, }, BaseBox, Decode, Either, Encode, }; @@ -39,6 +39,23 @@ impl VideoDecoderConfig { } } + pub fn from_hev1_box(b: &Hev1Box) -> Self { + let mut description = Vec::new(); + b.hvcc_box.encode(&mut description).expect("unreachable"); + description.drain(..8); // ボックスヘッダ部分を取り除く + + Self { + codec: format!( + "hev1.1.6.L90.B0" // b.c_profile_indication, + // b.avcc_box.profile_compatibility, + // b.avcc_box.avc_level_indication + ), + description, + coded_width: b.visual.width, + coded_height: b.visual.height, + } + } + pub fn from_vp08_box(b: &Vp08Box) -> Self { Self { codec: "vp8".to_owned(), @@ -163,6 +180,7 @@ impl Track { match sample_table.stbl_box().stsd_box.entries.first() { Some(SampleEntry::Avc1(_)) => (), + Some(SampleEntry::Hev1(_)) => (), Some(SampleEntry::Vp08(_)) => (), Some(SampleEntry::Vp09(_)) => (), Some(SampleEntry::Av01(_)) => (), @@ -256,6 +274,9 @@ impl Mp4 { SampleEntry::Avc1(b) => { video_configs.push(VideoDecoderConfig::from_avc1_box(b)); } + SampleEntry::Hev1(b) => { + video_configs.push(VideoDecoderConfig::from_hev1_box(b)); + } SampleEntry::Vp08(b) => { video_configs.push(VideoDecoderConfig::from_vp08_box(b)); } diff --git a/packages/mp4-media-stream/wasm/src/player.rs b/packages/mp4-media-stream/wasm/src/player.rs index 10728463..fbf33c17 100644 --- a/packages/mp4-media-stream/wasm/src/player.rs +++ b/packages/mp4-media-stream/wasm/src/player.rs @@ -180,6 +180,10 @@ impl TrackPlayer { let config = VideoDecoderConfig::from_avc1_box(b); WasmApi::create_video_decoder(self.player_id, config).await } + SampleEntry::Hev1(b) => { + let config = VideoDecoderConfig::from_hev1_box(b); + WasmApi::create_video_decoder(self.player_id, config).await + } SampleEntry::Vp08(b) => { let config = VideoDecoderConfig::from_vp08_box(b); WasmApi::create_video_decoder(self.player_id, config).await From e046102cac5171ce7e0479493aea77d624735059 Mon Sep 17 00:00:00 2001 From: Takeru Ohta Date: Fri, 6 Dec 2024 15:36:17 +0900 Subject: [PATCH 2/2] =?UTF-8?q?`Mp4MediaStream`=20=E3=81=AE=E5=AF=BE?= =?UTF-8?q?=E5=BF=9C=E3=82=B3=E3=83=BC=E3=83=87=E3=83=83=E3=82=AF=E3=81=AB?= =?UTF-8?q?=20H.265=20=E3=82=92=E8=BF=BD=E5=8A=A0=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGES.md | 2 ++ packages/mp4-media-stream/README.md | 1 + packages/mp4-media-stream/wasm/src/mp4.rs | 38 +++++++++++++++++++++-- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 28b00780..6077b34c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,8 @@ ## develop +- [ADD] `Mp4MediaStream` の対応コーデックに H.265 を追加する + - @sile - [ADD] `Mp4MediaStream` の対応コーデックに AV1 を追加する - @sile - [ADD] `Mp4MediaStream` の対応コーデックに VP9 を追加する diff --git a/packages/mp4-media-stream/README.md b/packages/mp4-media-stream/README.md index 681b567e..fab96df7 100644 --- a/packages/mp4-media-stream/README.md +++ b/packages/mp4-media-stream/README.md @@ -32,6 +32,7 @@ video.srcObject = stream - 映像: - H.264 + - H.265 - VP8 - VP9 - AV1 diff --git a/packages/mp4-media-stream/wasm/src/mp4.rs b/packages/mp4-media-stream/wasm/src/mp4.rs index 58663de5..6b601ef2 100644 --- a/packages/mp4-media-stream/wasm/src/mp4.rs +++ b/packages/mp4-media-stream/wasm/src/mp4.rs @@ -44,11 +44,43 @@ impl VideoDecoderConfig { b.hvcc_box.encode(&mut description).expect("unreachable"); description.drain(..8); // ボックスヘッダ部分を取り除く + let mut constraints = b + .hvcc_box + .general_constraint_indicator_flags + .get() + .to_be_bytes() + .to_vec(); + while constraints.len() > 1 && constraints.last() == Some(&0) { + constraints.pop(); + } + Self { + // ISO / IEC 14496-15 E.3 codec: format!( - "hev1.1.6.L90.B0" // b.c_profile_indication, - // b.avcc_box.profile_compatibility, - // b.avcc_box.avc_level_indication + "hev1.{}.{:X}.{}.{}", + match b.hvcc_box.general_profile_space.get() { + 1 => format!("A{}", b.hvcc_box.general_profile_idc.get()), + 2 => format!("B{}", b.hvcc_box.general_profile_idc.get()), + 3 => format!("C{}", b.hvcc_box.general_profile_idc.get()), + v => format!("{v}"), + }, + b.hvcc_box + .general_profile_compatibility_flags + .reverse_bits(), + format!( + "{}{}", + if b.hvcc_box.general_tier_flag.get() == 0 { + 'L' + } else { + 'H' + }, + b.hvcc_box.general_level_idc + ), + constraints + .into_iter() + .map(|b| format!("{:02X}", b)) + .collect::>() + .join(".") ), description, coded_width: b.visual.width,