LostBeard / SpawnDev.EBML

An extendable .Net library for reading and writing Extensible Binary Meta Language (aka EBML) documents. Includes schema for Matroska and WebM.
https://lostbeard.github.io/SpawnDev.EBML/
MIT License
9 stars 1 forks source link

Matroska : Auto-populate SeekHead when adding new children under Segment #5

Open Zeugma440 opened 4 weeks ago

Zeugma440 commented 4 weeks ago

Right now, when adding brand new children under the Segment node (e.g. adding Tags or Attachments to an untagged file), one needs to manually handle the creation of its index under SeekHead.

Problem is, when adding a new node from scratch, the client app has no idea what its position should be, as SpawnDev.EBML handles low-level I/O.

I can't find a proper way to get around it. My most recent attempt is as follows : 1- Add new Segment child node (e.g. Tags) 2- Add new Seek node under SeekHead with its SeekPosition valued to TEMP_INT64 3- Save the file 4- Reopen it 5- Read the position of the node created at Step 1 using BaseElement.Stream.Offset 6- Write that position on the SeekPosition node created at Step 2 instead of TEMP_INT64

There are two issues with that method :

Some of the spec does give suggestions to make files easier to edit after they are created. Leaving the SeekPosition the max (8 bytes) may be one of those suggestions.

Wouldn't that case be a solid argument to apply this suggestion? 😁

LostBeard commented 3 weeks ago

I should have Seek elements working correctly by tomorrow. 👍

I have rewritten a lot of the library and added a Blazor EBML Editor demo.

The library now uses (and includes) XML schema files:

It can now add and CRC-32 values thanks to Crc32.NET

LostBeard commented 3 weeks ago

Just figured it out.

Apparently the value written to \Segment\SeekHead\Seek'SeekPosition is the position of the target element not including the size of (any?) the SeekHead's size. This way, you don't have to take into account the size of the elements you are going to write to SeekHead.

SeekPosition = SeekIDelement.Position - SeekHead.Size

SeekIDelement.Position = SeekPosition + SeekHead.Size

This helps. 👍

Zeugma440 commented 3 weeks ago

I should have Seek elements working correctly by tomorrow. 👍

I have rewritten a lot of the library and added a Blazor EBML Editor demo.

Awesome! Thanks a bunch for your efforts 🤝 I can't wait to try it 😀

Just figured it out [...]

A-ha! I've been focused on the definition of Segment Position and didn't realize SeekPosition followed another logic. Man, the Matroska format is one hell of a beast...

LostBeard commented 3 weeks ago

A-ha! I've been focused on the definition of Segment Position and didn't realize SeekPosition followed another logic.

Nice, you appear to have been on the right track and I was off last night with my conclusion. I was seeing a pattern but I mixed up the numbers (I mixed up SeekHead position and size.) Segment Position appears to be the answer.

Here is a reference image using the Blazor EBML viewer I linked to.

EBML SeekPosition view

Red links SeekID and its target: 0x1549A966 (\Segment\Info) Yellow is the start position of Segment element data: 52
Purple is the position of the SeekID target: 213
Green is the SeekPosition: 161

So the SeekID target's position is:
SeekID target position = SeekPosition + Segment data start position
213 = 161 + 52
SeekPosition = SeekID target position - Segment data start position
161 = 213 - 52

👍

Matroska format is one hell of a beast...

lol I agree.

LostBeard commented 3 weeks ago

First preview of the editor with automatic SeekHead updating is up. When using the Blazor Editor, if you open devtools with the current build, there is some debug output indicating when the library checks SeekHead and updates it. CRC auto updating is also implemented and logs to console.

What app are you using to view .mka cover art?

You can click an element's value cell to edit it. Binary types can be saved to a file and a file can be loaded into a binary element's value.

I also added support for viewing images that are in binary elements. Just click on the binary element row and if the data is an image, it will try to show it in the right bottom preview pane.

LostBeard commented 3 weeks ago

Okay, I just updated the Blazor editor. SeekHead will now be auto updated and auto populated if it exists in a document. Auto populating means that if SeekHead exists and any of these top level elements, (Info, Tracks, Chapters, Cues, Attachments) also exist, a Seek entry will be created for each top level element if it does not exist. Document changes will cause the values to be updated if needed.

To demo:

You can then go into SeekHead and see the auto generated Seek element which contains SeekID and SeekPosition that target the Info element.

There are API settings to disable/enable auto-populate, crc auto update, etc. I will update the README with example code soon.

Zeugma440 commented 3 weeks ago

First of all thanks a bunch for all the hard work 💪

I'm done merging your updates with mine, and am still in the process of rewriting what I've done client-side to adapt to v2 API changes.

I'll get back to you soon regarding the two issues I posted.