diff options
author | metamuffin <metamuffin@disroot.org> | 2023-01-14 11:36:57 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2023-01-14 11:36:57 +0100 |
commit | 6c023ddeaa0894813fc74038af7568c2d867c052 (patch) | |
tree | 3d323c62fa8a6c2a7827d15061843fce8a7418f0 | |
parent | 855a8896175ee45a3376775203fa20e629d809b3 (diff) | |
download | jellything-6c023ddeaa0894813fc74038af7568c2d867c052.tar jellything-6c023ddeaa0894813fc74038af7568c2d867c052.tar.bz2 jellything-6c023ddeaa0894813fc74038af7568c2d867c052.tar.zst |
parsing should work
-rw-r--r-- | ebml/src/bin/experiment.rs | 4 | ||||
-rw-r--r-- | ebml/src/lib.rs | 45 | ||||
-rw-r--r-- | ebml/src/matroska.rs | 439 | ||||
-rw-r--r-- | ebml/src/read.rs | 86 | ||||
-rw-r--r-- | ebml_derive/src/lib.rs | 16 |
5 files changed, 346 insertions, 244 deletions
diff --git a/ebml/src/bin/experiment.rs b/ebml/src/bin/experiment.rs index 13b6895..c510bb5 100644 --- a/ebml/src/bin/experiment.rs +++ b/ebml/src/bin/experiment.rs @@ -6,7 +6,7 @@ fn main() { let f = File::open(std::env::args().skip(1).next().unwrap()).unwrap(); let mut r = EbmlReader::new(BufReader::new(f)); - loop { - println!("{:?}", r.read_tag()); + for tag in r { + println!("{:?}", tag); } } diff --git a/ebml/src/lib.rs b/ebml/src/lib.rs index 7445bbc..22af473 100644 --- a/ebml/src/lib.rs +++ b/ebml/src/lib.rs @@ -16,13 +16,6 @@ pub trait ValueFromBuf: Sized { impl ValueFromBuf for u64 { fn from_buf(buf: &[u8]) -> anyhow::Result<Self> { - // if buf.len() != 8 { - // bail!("u64 is not 64 bits long") - // } - // Ok((buf[0] as u64) << 24 - // | (buf[1] as u64) << 16 - // | (buf[2] as u64) << 8 - // | (buf[3] as u64) << 0) if buf.len() > 8 { bail!("u64 too big") } @@ -34,6 +27,34 @@ impl ValueFromBuf for u64 { Ok(val) } } +impl ValueFromBuf for i64 { + fn from_buf(buf: &[u8]) -> anyhow::Result<Self> { + if buf.len() > 8 { + bail!("i64 too big") + } + Ok(if buf[0] > 127 { + if buf.len() == 8 { + i64::from_be_bytes(buf.try_into().unwrap()) + } else { + -((1 << (buf.len() * 8)) - (u64::from_buf(buf)? as i64)) + } + } else { + u64::from_buf(buf)? as i64 + }) + } +} +impl ValueFromBuf for f64 { + fn from_buf(buf: &[u8]) -> anyhow::Result<Self> { + Ok(if buf.len() == 4 { + f32::from_be_bytes(buf.try_into().unwrap()) as f64 + } else if buf.len() == 8 { + f64::from_be_bytes(buf.try_into().unwrap()) + } else { + bail!("float is not 4 or 8 bytes long"); + }) + } +} + impl ValueFromBuf for Vec<u8> { fn from_buf(buf: &[u8]) -> anyhow::Result<Self> { Ok(buf.to_vec()) @@ -44,3 +65,13 @@ impl ValueFromBuf for String { Ok(String::from_utf8(Vec::from(buf))?) } } +impl ValueFromBuf for Master { + /// this has an internal usage, where buf has len of 1, when an end should be constructed + fn from_buf(buf: &[u8]) -> anyhow::Result<Self> { + Ok(match buf.len() { + 0 => Master::Start, + 1 => Master::End, + _ => unreachable!(), + }) + } +} diff --git a/ebml/src/matroska.rs b/ebml/src/matroska.rs index c9198bb..9678e80 100644 --- a/ebml/src/matroska.rs +++ b/ebml/src/matroska.rs @@ -31,6 +31,7 @@ define_ebml! { FileUsedStartTime[0x4661]: Uint, }, }, + Chapters[0x1043A770]: { EditionEntry[0x45B9]: { ChapPterAtom[0xB6]: { @@ -69,259 +70,259 @@ define_ebml! { }, Cluster[0x1F43B675]: { - #[id=0xA0] BlockGroup: { - #[id=0xA1] Block(Binary), - #[id=0x75A1] BlockAdditions: { - #[id=0xA6] BlockMore: { - #[id=0xEE] BlockAddID(Uint), - #[id=0xA5] BlockAdditional(Binary), + BlockGroup[0xA0]: { + Block[0xA1]: Binary, + BlockAdditions[0x75A1]: { + BlockMore[0xA6]: { + BlockAddID[0xEE]: Uint, + BlockAdditional[0xA5]: Binary, }, }, - #[id=0x9B] BlockDuration(Uint), - #[id=0xA2] BlockVirtual(Binary), - #[id=0xA4] CodecState(Binary), - #[id=0x75A2] DiscardPadding(Integer), - #[id=0xFB] ReferenceBlock(Integer), - #[id=0xC8] ReferenceFrame: { - #[id=0xC9] ReferenceOffset(Uint), - #[id=0xCA] ReferenceTimestamp(Uint), + BlockDuration[0x9B]: Uint, + BlockVirtual[0xA2]: Binary, + CodecState[0xA4]: Binary, + DiscardPadding[0x75A2]: Int, + ReferenceBlock[0xFB]: Int, + ReferenceFrame[0xC8]: { + ReferenceOffset[0xC9]: Uint, + ReferenceTimestamp[0xCA]: Uint, }, - #[id=0xFA] ReferencePriority(Uint), - #[id=0xFD] ReferenceVirtual(Integer), - #[id=0x8E] Slices: { - #[id=0xE8] TimeSlice: { - #[id=0xCB] BlockAdditionID(Uint), - #[id=0xCE] Delay(Uint), - #[id=0xCD] FrameNumber(Uint), - #[id=0xCC] LaceNumber(Uint), - #[id=0xCF] SliceDuration(Uint), + ReferencePriority[0xFA]: Uint, + ReferenceVirtual[0xFD]: Int, + Slices[0x8E]: { + TimeSlice[0xE8]: { + BlockAdditionID[0xCB]: Uint, + Delay[0xCE]: Uint, + FrameNumber[0xCD]: Uint, + LaceNumber[0xCC]: Uint, + SliceDuration[0xCF]: Uint, }, }, }, - #[id=0xAF] EncryptedBlock(Binary), - #[id=0xA7] Position(Uint), - #[id=0xAB] PrevSize(Uint), - #[id=0x5854] SilentTracks: { - #[id=0x58D7] SilentTrackNumber(Uint), + EncryptedBlock[0xAF]: Binary, + Position[0xA7]: Uint, + PrevSize[0xAB]: Uint, + SilentTracks[0x5854]: { + SilentTrackNumber[0x58D7]: Uint, }, - #[id=0xA3] SimpleBlock(Binary), - #[id=0xE7] Timestamp(Uint), - } + SimpleBlock[0xA3]: Binary, + Timestamp[0xE7]: Uint, + }, - #[id=0x1C53BB6B] Cues: { - #[id=0xBB] CuePoint: { - #[id=0xB3] CueTime(Uint), - #[id=0xB7] CueTrackPositions: { - #[id=0x5378] CueBlockNumber(Uint), - #[id=0xF1] CueClusterPosition(Uint), - #[id=0xEA] CueCodecState(Uint), - #[id=0xB2] CueDuration(Uint), - #[id=0xDB] CueReference: { - #[id=0x97] CueRefCluster(Uint), - #[id=0xEB] CueRefCodecState(Uint), - #[id=0x535F] CueRefNumber(Uint), - #[id=0x96] CueRefTime(Uint), + Cues[0x1C53BB6B]: { + CuePoint[0xBB]: { + CueTime[0xB3]: Uint, + CueTrackPositions[0xB7]: { + CueBlockNumber[0x5378]: Uint, + CueClusterPosition[0xF1]: Uint, + CueCodecState[0xEA]: Uint, + CueDuration[0xB2]: Uint, + CueReference[0xDB]: { + CueRefCluster[0x97]: Uint, + CueRefCodecState[0xEB]: Uint, + CueRefNumber[0x535F]: Uint, + CueRefTime[0x96]: Uint, }, - #[id=0xF0] CueRelativePosition(Uint), - #[id=0xF7] CueTrack(Uint), + CueRelativePosition[0xF0]: Uint, + CueTrack[0xF7]: Uint, }, }, }, - #[id=0x1549A966] Info: { - #[id=0x6924] ChapterTranslate: { - #[id=0x69BF] ChapterTranslateCodec(Uint), - #[id=0x69FC] ChapterTranslateEditionUID(Uint), - #[id=0x69A5] ChapterTranslateID(Binary), - } - #[id=0x4461] DateUTC(Integer), - #[id=0x4489] Duration(Float), - #[id=0x4D80] MuxingApp(Utf8), - #[id=0x3E83BB] NextFilename(Utf8), - #[id=0x3EB923] NextUID(Binary), - #[id=0x3C83AB] PrevFilename(Utf8), - #[id=0x3CB923] PrevUID(Binary), - #[id=0x4444] SegmentFamily(Binary), - #[id=0x7384] SegmentFilename(Utf8), - #[id=0x73A4] SegmentUID(Binary), - #[id=0x2AD7B1] TimestampScale(Uint), - #[id=0x7BA9] Title(Utf8), - #[id=0x5741] WritingApp(Utf8), + Info[0x1549A966]: { + ChapterTranslate[0x6924]: { + ChapterTranslateCodec[0x69BF]: Uint, + ChapterTranslateEditionUID[0x69FC]: Uint, + ChapterTranslateID[0x69A5]: Binary, + }, + DateUTC[0x4461]: Int, + Duration[0x4489]: Float, + MuxingApp[0x4D80]: Utf8, + NextFilename[0x3E83BB]: Utf8, + NextUID[0x3EB923]: Binary, + PrevFilename[0x3C83AB]: Utf8, + PrevUID[0x3CB923]: Binary, + SegmentFamily[0x4444]: Binary, + SegmentFilename[0x7384]: Utf8, + SegmentUID[0x73A4]: Binary, + TimestampScale[0x2AD7B1]: Uint, + Title[0x7BA9]: Utf8, + WritingApp[0x5741]: Utf8, }, - #[id=0x114D9B74] SeekHead: { - #[id=0x4DBB] Seek: { - #[id=0x53AB] SeekID(Binary), - #[id=0x53AC] SeekPosition(Uint), + SeekHead[0x114D9B74]: { + Seek[0x4DBB]: { + SeekID[0x53AB]: Binary, + SeekPosition[0x53AC]: Uint, }, }, - #[id=0x1254C367] Tags: { - #[id=0x7373] Tag: { - #[id=0x67C8] SimpleTag: { - #[id=0x4485] TagBinary(Binary), - #[id=0x4484] TagDefault(Uint), - #[id=0x44B4] TagDefaultBogus(Uint), - #[id=0x447A] TagLanguage(Utf8), - #[id=0x447B] TagLanguageIETF(Utf8), - #[id=0x45A3] TagName(Utf8), - #[id=0x4487] TagString(Utf8), + Tags[0x1254C367]: { + Tag[0x7373]: { + SimpleTag[0x67C8]: { + TagBinary[0x4485]: Binary, + TagDefault[0x4484]: Uint, + TagDefaultBogus[0x44B4]: Uint, + TagLanguage[0x447A]: Utf8, + TagLanguageIETF[0x447B]: Utf8, + TagName[0x45A3]: Utf8, + TagString[0x4487]: Utf8, }, - #[id=0x63C0] Targets: { - #[id=0x63C6] TagAttachmentUID(Uint), - #[id=0x63C4] TagChapterUID(Uint), - #[id=0x63C9] TagEditionUID(Uint), - #[id=0x63C5] TagTrackUID(Uint), - #[id=0x63CA] TargetType(Utf8), - #[id=0x68CA] TargetTypeValue(Uint), + Targets[0x63C0]: { + TagAttachmentUID[0x63C6]: Uint, + TagChapterUID[0x63C4]: Uint, + TagEditionUID[0x63C9]: Uint, + TagTrackUID[0x63C5]: Uint, + TargetType[0x63CA]: Utf8, + TargetTypeValue[0x68CA]: Uint, }, }, }, - #[id=0x1654AE6B] Tracks: { - #[id=0xAE] TrackEntry: { - #[id=0x7446] AttachmentLink(Uint), - #[id=0xE1] Audio: { - #[id=0x6264] BitDepth(Uint), - #[id=0x7D7B] ChannelPositions(Binary), - #[id=0x9F] Channels(Uint), - #[id=0x78B5] OutputSamplingFrequency(Float), - #[id=0xB5] SamplingFrequency(Float), - } - #[id=0x41E4] BlockAdditionMapping: { - #[id=0x41ED] BlockAddIDExtraData(Binary), - #[id=0x41A4] BlockAddIDName(Utf8), - #[id=0x41E7] BlockAddIDType(Uint), - #[id=0x41F0] BlockAddIDValue(Uint), - } - #[id=0xAA] CodecDecodeAll(Uint), - #[id=0x56AA] CodecDelay(Uint), - #[id=0x26B240] CodecDownloadURL(Utf8), - #[id=0x86] CodecID(Utf8), - #[id=0x3B4040] CodecInfoURL(Utf8), - #[id=0x258688] CodecName(Utf8), - #[id=0x63A2] CodecPrivate(Binary), - #[id=0x3A9697] CodecSettings(Utf8), - #[id=0x6D80] ContentEncodings: { - #[id=0x6240] ContentEncoding: { - #[id=0x5034] ContentCompression: { - #[id=0x4254] ContentCompAlgo(Uint), - #[id=0x4255] ContentCompSettings(Binary), + Tracks[0x1654AE6B]: { + TrackEntry[0xAE]: { + AttachmentLink[0x7446]: Uint, + Audio[0xE1]: { + BitDepth[0x6264]: Uint, + ChannelPositions[0x7D7B]: Binary, + Channels[0x9F]: Uint, + OutputSamplingFrequency[0x78B5]: Float, + SamplingFrequency[0xB5]: Float, + }, + BlockAdditionMapping[0x41E4]: { + BlockAddIDExtraData[0x41ED]: Binary, + BlockAddIDName[0x41A4]: Utf8, + BlockAddIDType[0x41E7]: Uint, + BlockAddIDValue[0x41F0]: Uint, + }, + CodecDecodeAll[0xAA]: Uint, + CodecDelay[0x56AA]: Uint, + CodecDownloadURL[0x26B240]: Utf8, + CodecID[0x86]: Utf8, + CodecInfoURL[0x3B4040]: Utf8, + CodecName[0x258688]: Utf8, + CodecPrivate[0x63A2]: Binary, + CodecSettings[0x3A9697]: Utf8, + ContentEncodings[0x6D80]: { + ContentEncoding[0x6240]: { + ContentCompression[0x5034]: { + ContentCompAlgo[0x4254]: Uint, + ContentCompSettings[0x4255]: Binary, }, - #[id=0x5031] ContentEncodingOrder(Uint), - #[id=0x5032] ContentEncodingScope(Uint), - #[id=0x5033] ContentEncodingType(Uint), - #[id=0x5035] ContentEncryption: { - #[id=0x47E7] ContentEncAESSettings: { - #[id=0x47E8] AESSettingsCipherMode(Uint), - } - #[id=0x47E1] ContentEncAlgo(Uint), - #[id=0x47E2] ContentEncKeyID(Binary), - #[id=0x47E5] ContentSigAlgo(Uint), - #[id=0x47E6] ContentSigHashAlgo(Uint), - #[id=0x47E4] ContentSigKeyID(Binary), - #[id=0x47E3] ContentSignature(Binary), + ContentEncodingOrder[0x5031]: Uint, + ContentEncodingScope[0x5032]: Uint, + ContentEncodingType[0x5033]: Uint, + ContentEncryption[0x5035]: { + ContentEncAESSettings[0x47E7]: { + AESSettingsCipherMode[0x47E8]: Uint, + }, + ContentEncAlgo[0x47E1]: Uint, + ContentEncKeyID[0x47E2]: Binary, + ContentSigAlgo[0x47E5]: Uint, + ContentSigHashAlgo[0x47E6]: Uint, + ContentSigKeyID[0x47E4]: Binary, + ContentSignature[0x47E3]: Binary, }, }, }, - #[id=0x234E7A] DefaultDecodedFieldDuration(Uint), - #[id=0x23E383] DefaultDuration(Uint), - #[id=0x55AF] FlagCommentary(Uint), - #[id=0x88] FlagDefault(Uint), - #[id=0xB9] FlagEnabled(Uint), - #[id=0x55AA] FlagForced(Uint), - #[id=0x55AB] FlagHearingImpaired(Uint), - #[id=0x9C] FlagLacing(Uint), - #[id=0x55AE] FlagOriginal(Uint), - #[id=0x55AD] FlagTextDescriptions(Uint), - #[id=0x55AC] FlagVisualImpaired(Uint), - #[id=0x22B59C] Language(Utf8), - #[id=0x22B59D] LanguageIETF(Utf8), - #[id=0x55EE] MaxBlockAdditionID(Uint), - #[id=0x6DF8] MaxCache(Uint), - #[id=0x6DE7] MinCache(Uint), - #[id=0x536E] Name(Utf8), - #[id=0x56BB] SeekPreRoll(Uint), - #[id=0xD7] TrackNumber(Uint), - #[id=0x537F] TrackOffset(Integer), - #[id=0xE2] TrackOperation: { - #[id=0xE3] TrackCombinePlanes: { - #[id=0xE4] TrackPlane: { - #[id=0xE6] TrackPlaneType(Uint), - #[id=0xE5] TrackPlaneUID(Uint), + DefaultDecodedFieldDuration[0x234E7A]: Uint, + DefaultDuration[0x23E383]: Uint, + FlagCommentary[0x55AF]: Uint, + FlagDefault[0x88]: Uint, + FlagEnabled[0xB9]: Uint, + FlagForced[0x55AA]: Uint, + FlagHearingImpaired[0x55AB]: Uint, + FlagLacing[0x9C]: Uint, + FlagOriginal[0x55AE]: Uint, + FlagTextDescriptions[0x55AD]: Uint, + FlagVisualImpaired[0x55AC]: Uint, + Language[0x22B59C]: Utf8, + LanguageIETF[0x22B59D]: Utf8, + MaxBlockAdditionID[0x55EE]: Uint, + MaxCache[0x6DF8]: Uint, + MinCache[0x6DE7]: Uint, + Name[0x536E]: Utf8, + SeekPreRoll[0x56BB]: Uint, + TrackNumber[0xD7]: Uint, + TrackOffset[0x537F]: Int, + TrackOperation[0xE2]: { + TrackCombinePlanes[0xE3]: { + TrackPlane[0xE4]: { + TrackPlaneType[0xE6]: Uint, + TrackPlaneUID[0xE5]: Uint, }, }, - #[id=0xE9] TrackJoinBlocks: { - #[id=0xED] TrackJoinUID(Uint), + TrackJoinBlocks[0xE9]: { + TrackJoinUID[0xED]: Uint, }, - } - #[id=0x6FAB] TrackOverlay(Uint), - #[id=0x23314F] TrackTimestampScale(Float), - #[id=0x6624] TrackTranslate: { - #[id=0x66BF] TrackTranslateCodec(Uint), - #[id=0x66FC] TrackTranslateEditionUID(Uint), - #[id=0x66A5] TrackTranslateTrackID(Binary), }, - #[id=0x83] TrackType(Uint), - #[id=0x73C5] TrackUID(Uint), - #[id=0xC4] TrickMasterTrackSegmentUID(Binary), - #[id=0xC7] TrickMasterTrackUID(Uint), - #[id=0xC6] TrickTrackFlag(Uint), - #[id=0xC1] TrickTrackSegmentUID(Binary), - #[id=0xC0] TrickTrackUID(Uint), - #[id=0xE0] Video: { - #[id=0x53C0] AlphaMode(Uint), - #[id=0x54B3] AspectRatioType(Uint), - #[id=0x55B0] Colour: { - #[id=0x55B2] BitsPerChannel(Uint), - #[id=0x55B5] CbSubsamplingHorz(Uint), - #[id=0x55B6] CbSubsamplingVert(Uint), - #[id=0x55B7] ChromaSitingHorz(Uint), - #[id=0x55B8] ChromaSitingVert(Uint), - #[id=0x55B3] ChromaSubsamplingHorz(Uint), - #[id=0x55B4] ChromaSubsamplingVert(Uint), - #[id=0x55D0] MasteringMetadata: { - #[id=0x55D9] LuminanceMax(Float), - #[id=0x55DA] LuminanceMin(Float), - #[id=0x55D5] PrimaryBChromaticityX(Float), - #[id=0x55D6] PrimaryBChromaticityY(Float), - #[id=0x55D3] PrimaryGChromaticityX(Float), - #[id=0x55D4] PrimaryGChromaticityY(Float), - #[id=0x55D1] PrimaryRChromaticityX(Float), - #[id=0x55D2] PrimaryRChromaticityY(Float), - #[id=0x55D7] WhitePointChromaticityX(Float), - #[id=0x55D8] WhitePointChromaticityY(Float), + TrackOverlay[0x6FAB]: Uint, + TrackTimestampScale[0x23314F]: Float, + TrackTranslate[0x6624]: { + TrackTranslateCodec[0x66BF]: Uint, + TrackTranslateEditionUID[0x66FC]: Uint, + TrackTranslateTrackID[0x66A5]: Binary, + }, + TrackType[0x83]: Uint, + TrackUID[0x73C5]: Uint, + TrickMasterTrackSegmentUID[0xC4]: Binary, + TrickMasterTrackUID[0xC7]: Uint, + TrickTrackFlag[0xC6]: Uint, + TrickTrackSegmentUID[0xC1]: Binary, + TrickTrackUID[0xC0]: Uint, + Video[0xE0]: { + AlphaMode[0x53C0]: Uint, + AspectRatioType[0x54B3]: Uint, + Colour[0x55B0]: { + BitsPerChannel[0x55B2]: Uint, + CbSubsamplingHorz[0x55B5]: Uint, + CbSubsamplingVert[0x55B6]: Uint, + ChromaSitingHorz[0x55B7]: Uint, + ChromaSitingVert[0x55B8]: Uint, + ChromaSubsamplingHorz[0x55B3]: Uint, + ChromaSubsamplingVert[0x55B4]: Uint, + MasteringMetadata[0x55D0]: { + LuminanceMax[0x55D9]: Float, + LuminanceMin[0x55DA]: Float, + PrimaryBChromaticityX[0x55D5]: Float, + PrimaryBChromaticityY[0x55D6]: Float, + PrimaryGChromaticityX[0x55D3]: Float, + PrimaryGChromaticityY[0x55D4]: Float, + PrimaryRChromaticityX[0x55D1]: Float, + PrimaryRChromaticityY[0x55D2]: Float, + WhitePointChromaticityX[0x55D7]: Float, + WhitePointChromaticityY[0x55D8]: Float, }, - #[id=0x55B1] MatrixCoefficients(Uint), - #[id=0x55BC] MaxCLL(Uint), - #[id=0x55BD] MaxFALL(Uint), - #[id=0x55BB] Primaries(Uint), - #[id=0x55B9] Range(Uint), - #[id=0x55BA] TransferCharacteristics(Uint), + MatrixCoefficients[0x55B1]: Uint, + MaxCLL[0x55BC]: Uint, + MaxFALL[0x55BD]: Uint, + Primaries[0x55BB]: Uint, + Range[0x55B9]: Uint, + TransferCharacteristics[0x55BA]: Uint, }, - #[id=0x54BA] DisplayHeight(Uint), - #[id=0x54B2] DisplayUnit(Uint), - #[id=0x54B0] DisplayWidth(Uint), - #[id=0x9D] FieldOrder(Uint), - #[id=0x9A] FlagInterlaced(Uint), - #[id=0x2383E3] FrameRate(Float), - #[id=0x2FB523] GammaValue(Float), - #[id=0x53B9] OldStereoMode(Uint), - #[id=0x54AA] PixelCropBottom(Uint), - #[id=0x54CC] PixelCropLeft(Uint), - #[id=0x54DD] PixelCropRight(Uint), - #[id=0x54BB] PixelCropTop(Uint), - #[id=0xBA] PixelHeight(Uint), - #[id=0xB0] PixelWidth(Uint), - #[id=0x7670] Projection: { - #[id=0x7674] ProjectionPosePitch(Float), - #[id=0x7675] ProjectionPoseRoll(Float), - #[id=0x7673] ProjectionPoseYaw(Float), - #[id=0x7672] ProjectionPrivate(Binary), - #[id=0x7671] ProjectionType(Uint), + DisplayHeight[0x54BA]: Uint, + DisplayUnit[0x54B2]: Uint, + DisplayWidth[0x54B0]: Uint, + FieldOrder[0x9D]: Uint, + FlagInterlaced[0x9A]: Uint, + FrameRate[0x2383E3]: Float, + GammaValue[0x2FB523]: Float, + OldStereoMode[0x53B9]: Uint, + PixelCropBottom[0x54AA]: Uint, + PixelCropLeft[0x54CC]: Uint, + PixelCropRight[0x54DD]: Uint, + PixelCropTop[0x54BB]: Uint, + PixelHeight[0xBA]: Uint, + PixelWidth[0xB0]: Uint, + Projection[0x7670]: { + ProjectionPosePitch[0x7674]: Float, + ProjectionPoseRoll[0x7675]: Float, + ProjectionPoseYaw[0x7673]: Float, + ProjectionPrivate[0x7672]: Binary, + ProjectionType[0x7671]: Uint, }, - #[id=0x53B8] StereoMode(Uint), - #[id=0x2EB524] UncompressedFourCC(Binary), + StereoMode[0x53B8]: Uint, + UncompressedFourCC[0x2EB524]: Binary, }, }, }, diff --git a/ebml/src/read.rs b/ebml/src/read.rs index 23b4e21..3e02e18 100644 --- a/ebml/src/read.rs +++ b/ebml/src/read.rs @@ -1,13 +1,25 @@ use anyhow::{bail, Result}; -use std::io::{Read, Seek}; +use log::warn; +use std::{ + collections::VecDeque, + io::{Read, Seek}, +}; use crate::matroska::MatroskaTag; trait ReadAndSeek: Read + Seek {} impl<T: Read + Seek> ReadAndSeek for T {} +#[derive(Debug, Clone, Copy)] +pub struct StackTag { + end: Option<usize>, + id: u64, +} + pub struct EbmlReader { inner: Box<dyn ReadAndSeek>, + stack: Vec<StackTag>, + queue: VecDeque<MatroskaTag>, pub position: usize, } @@ -18,7 +30,9 @@ pub trait EbmlRead: Sized { impl EbmlReader { pub fn new<T: Seek + Read + 'static>(inner: T) -> Self { Self { + queue: VecDeque::new(), inner: Box::new(inner), + stack: vec![], position: 0, } } @@ -64,14 +78,70 @@ impl EbmlReader { pub fn read_tag_size(&mut self) -> Result<EbmlSize> { Ok(EbmlSize::from_vint(self.read_vint_len()?)) } - pub fn read_tag(&mut self) -> Result<MatroskaTag> { + pub fn read_stuff(&mut self) -> Result<()> { + if let Some(e) = self.stack.last().map(|e| *e) { + if let Some(end) = e.end { + if self.position >= end { + if self.position != end { + warn!("we missed the end") + } + self.stack.pop(); + self.queue.push_back(MatroskaTag::parse(e.id, &[0])?); + } + } + } + let id = self.read_tag_id()?; let size = self.read_tag_size()?; - if MatroskaTag::is_master(id)? { - Ok(MatroskaTag::parse(id, &[])?) + let is_master = MatroskaTag::is_master(id)?; + let tag = if is_master { + MatroskaTag::parse(id, &[])? } else { let data = self.read_buf(size)?; - Ok(MatroskaTag::parse(id, &data)?) + MatroskaTag::parse(id, &data)? + }; + + if let Some(path) = tag.path() { + // we have slightly different rules for closing tags implicitly + // this closes as many tags as needed to make the next tag a valid child + while let Some(tag @ StackTag { end: None, .. }) = self.stack.last() { + let mut valid_child = false; + for p in path { + if *p == tag.id { + valid_child = true; + } + } + if valid_child { + break; + } else { + self.queue + .push_back(MatroskaTag::parse(self.stack.pop().unwrap().id, &[0])?); + } + } + } + + if is_master { + self.stack.push(StackTag { + end: size.some().map(|s| s + self.position), + id, + }); + } + self.queue.push_back(tag); + Ok(()) + } +} + +impl Iterator for EbmlReader { + type Item = Result<MatroskaTag>; + + fn next(&mut self) -> Option<Self::Item> { + if let Some(t) = self.queue.pop_front() { + Some(Ok(t)) + } else { + match self.read_stuff() { + Ok(()) => self.next(), + Err(e) => Some(Err(e)), + } } } } @@ -89,6 +159,12 @@ impl EbmlSize { Self::Exact(value as usize) } } + pub fn some(self) -> Option<usize> { + match self { + EbmlSize::Exact(s) => Some(s), + EbmlSize::Unknown => None, + } + } } impl Into<usize> for EbmlSize { fn into(self) -> usize { diff --git a/ebml_derive/src/lib.rs b/ebml_derive/src/lib.rs index f3957df..fc8af7d 100644 --- a/ebml_derive/src/lib.rs +++ b/ebml_derive/src/lib.rs @@ -25,7 +25,9 @@ pub fn define_ebml(ts: TokenStream) -> TokenStream { syn::parse2::<FieldsUnnamed>(match e.r#type.clone() { None => quote!((Master)), Some(r#type) => match r#type.as_str() { + "Int" => quote!((i64)), "Uint" => quote!((u64)), + "Float" => quote!((f64)), "Utf8" => quote!((String)), "Binary" => quote!((Vec<u8>)), _ => panic!("unsupported type {}", r#type), @@ -53,17 +55,9 @@ pub fn define_ebml(ts: TokenStream) -> TokenStream { let parse_match = tags .iter() - .map( - |Tag { - id, name, r#type, .. - }| { - if let Some(_) = r#type { - quote! { #id => Self::#name(crate::ValueFromBuf::from_buf(data)?) } - } else { - quote! { #id => Self::#name(Master::Start) } - } - }, - ) + .map(|Tag { id, name, .. }| { + quote! { #id => Self::#name(crate::ValueFromBuf::from_buf(data)?) } + }) .collect::<Vec<_>>(); let master_match = tags .iter() |