You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The pattern file [mxv-container.hexpat](./mxv-container.hexpat) contains the current state of my reverse engineering effort.
4
+
The file can be used with [ImHex] to inspect any MXV file:
5
+
6
+

7
+
8
+
## Format basics
9
+
10
+
It's a really simple video format, as it is just a bunch of JPEG images and PCM audio data stored in some relatively simple data structures.
11
+
Theoretically (and practically) you can grab the JPEG and PCM data without modifying it, put it into another container (like AVI), and then be able to play it back with non MAGIX software.
12
+
And that without losing any image/sound quality, as there is no transcoding or re-encoding happening.
13
+
And that's basically what this project is about.
14
+
15
+
The structure of a MXV container is similar to [RIFF].
16
+
The difference is that most fields like the identifiers and lengths have a width of 64 bits, which makes sense as this container likely contains video data larger than 4GiB.
17
+
18
+
The root chunk has an identifier of `MXRIFF64`.
19
+
The `FormType` of the root chunk describes the type of data this container holds.
20
+
My test video files all have it set to `MXJVID64`, but it's likely that MAGIX also uses this container for other purposes.
21
+
For MXV files it's most likely always set to `MXJVID64`.
22
+
23
+
The root chunk has the following sub-chunks:
24
+
25
+
-`MXJVH264`: This contains information about the number of video and audio frames, the video resolution, and some unimportant and/or unknown data.
26
+
-`MXJVHD64`: Same as `MXJVH264`, but shorter.
27
+
Likely from an older version, and it may just be there for compatibility reasons.
28
+
It's also missing all of the audio information.
29
+
-`MXMFMT64`: Wave format stuff. Like sample rate, number of channels, ...
30
+
-`MXJVCO64`: Unknown.
31
+
-`MXJVPD64`: Unknown.
32
+
-`MXLIST64`: A list of sub-chunks with `ContentType` set to `MXJVFL64`.
33
+
It contains all video and audio frame chunks.
34
+
There may be fewer frames listed here than the real count of video frames, as the format can deduplicate frames.
35
+
-`MXJVFT64`: Contains an array of file offsets to all video frame chunks.
36
+
There is one more entry than there are frames.
37
+
But this is most likely there due the need to calculate the chunk length, as the array only stores offsets.
38
+
Multiple entries here can point to a single frame chunk.
39
+
-`MXLIST32`: A list of sub-chunks with `ContentType` set to `MXJVTL32`.
40
+
It contains file offsets and byte lengths of all video and audio frame chunks.
41
+
Multiple entries here can point to a single frame chunk.
42
+
43
+
The correct way to decode/read video frames is to iterate over the `MXJVTL32` list or the `MXJVFT64` chunk.
44
+
Using `MXJVFL64` directly will result in fewer frames and therefore video/audio sync issues.
45
+
This is because `MXJVFL64` is only a storage container for the video and audio frames, the correct order and number of times a frame is shown is stored in `MXJVTL32` and/or `MXJVFT64`.
46
+
Theoretically the frame data in `MXJVFL64` could be written out of order, and still be played back fine as long as `MXJVTL32` and/or `MXJVFT64` point to the correct chunks.
47
+
48
+
## How can i help?
49
+
50
+
If you have some MAGIX video editing software you can provide small synthetic test video files varying by the following parameters:
51
+
52
+
- Framerate
53
+
- Pixel aspect ratio
54
+
- Audio sample rate
55
+
- Audio channels
56
+
- Audio bit depth
57
+
- Or anything else you can think of
58
+
59
+
With that i would be able to extend the support of these features.
60
+
61
+
Also, you can use [ImHex] to inspect files yourself, and check them against info that you can obtain from your MAGIX video software.
62
+
63
+
Feel free to open a new issue if you find any discrepancies in the current documentation or have any helpful information.
64
+
65
+
## Old grammar file
66
+
67
+
[MXV Container.grammar](./MXV%20Container.grammar) is a grammar file made with [hexinator] that helps to decode and inspect MXV files.
68
+
It's also be compatible with [Synalyze It!].
69
+
70
+
As i don't have access to a full version of hexinator or similar software, i'll not continue to work on `MXV Container.grammar`.
bool DecodeAll in; // When false: Will limit decoding of lists by "ListByteLimit" bytes, and will not decode pointers.
6
+
bool DecodePointers in; // When true: Will decode offsets in lookup tables as pointers. It's slow as it will decode chunks several times.
7
+
u64 ListByteLimit = 1000000;
8
+
9
+
u64 VideoFrames out; // Number of detected video frames. There may be fewer frames shown here, as the format is able to deduplicate frames.
10
+
u64 AudioFrames out; // Number of detected audio frames. There may be fewer frames shown here, as the format is able to deduplicate frames.
11
+
u64 AudioSamples out; // Number of detected audio samples.
12
+
u64 VFTEEntries out; // Number of detected VFTE entries. This corresponds to the real number of video frames.
13
+
u64 AFTEEntries out; // Number of detected AFTE etries. This corresponds to the real number of audio frames.
14
+
u64 MXJVFT64Entries out; // Number of detected VFT entries.
15
+
u64 MaxVideoChunkSize out; // Size of the largest video frame chunk.
16
+
u64 MaxAudioChunkSize out; // Size of the largest video frame chunk.
17
+
18
+
import hex.core;
19
+
import std.io;
20
+
import std.sys;
21
+
22
+
// Form type, aka "File type".
23
+
enum MXFormType : u64 {
24
+
MXJVID64 = 0x34364449564A584D, // Magix Video File (MXV).
25
+
};
26
+
27
+
// Chunk32 identifiers.
28
+
enum MXIdentifier32 : u32 {
29
+
MXVFTE = 0x45544656, // References to a video frame chunk (Video frame table entry?).
30
+
MXAFTE = 0x45544641, // References to a audio frame chunk (Audio frame table entry?).
31
+
};
32
+
33
+
// Chunk64 identifiers.
34
+
enum MXIdentifier64 : u64 {
35
+
MXRIFF64 = 0x343646464952584D, // Root chunk.
36
+
MXLIST32 = 0x32335453494C584D, // List of sub-chunks.
37
+
MXLIST64 = 0x34365453494C584D, // List of sub-chunks.
38
+
39
+
MXJVAF64 = 0x34364641564A584D, // Audio frame data as raw PCM data.
40
+
MXJVCO64 = 0x34364F43564A584D, // Guess: Video color something?
41
+
MXJVFT64 = 0x34365446564A584D, // Video frame table: File offsets for fast seeking of specific frames. Contains one more entry than there are video frames in my test files. This is probably due to the list not containing any size information, and therefore the difference between the current and next entry is used. Therefore the entry for the last frame needs another entry after it.
42
+
MXJVH264 = 0x34363248564A584D, // Video format info.
43
+
MXJVHD64 = 0x34364448564A584D, // Older (and shorter) version of the video format info chunk.
44
+
MXJVPD64 = 0x34364450564A584D,
45
+
MXJVVF64 = 0x34364656564A584D, // Video frame data as a JPEG.
46
+
MXWFMT64 = 0x3436544D4657584D, // Audioformat info (Wave format).
47
+
};
48
+
49
+
// List content types.
50
+
enum MXContentType64 : u64 {
51
+
MXJVFL64 = 0x34364C46564A584D, // List of video and audio frames. ("Video Frame List"?)
52
+
MXJVTL32 = 0x32334C54564A584D, // List of offsets of the respective video and audio chunks.
53
+
};
54
+
55
+
using Chunk64;
56
+
57
+
struct ChunkMXAFTE {
58
+
if (DecodePointers) {Chunk64 *AudioFrameChunk: u64;} else {u64 AudioFrameChunkOffset;}
59
+
u32 ChunkSize;
60
+
u64 StartSample;
61
+
u32 Samples;
62
+
63
+
AFTEEntries += 1;
64
+
};
65
+
66
+
struct ChunkMXVFTE {
67
+
if (DecodePointers) {Chunk64 *VideoFrameChunk: u64;} else {u64 VideoFrameChunkOffset;}
if (MaxAudioChunkSize < parent.Length) {MaxAudioChunkSize = parent.Length;}
113
+
};
114
+
115
+
struct ChunkMXJVCO64 {
116
+
u8 Data[24];
117
+
};
118
+
119
+
struct ChunkMXJVFT64 {
120
+
u64 VideoFrameOffset[parent.Length/8];
121
+
122
+
MXJVFT64Entries += parent.Length/8;
123
+
};
124
+
125
+
struct ChunkMXJVH264 {
126
+
u32; // Seems to be always 112, the size of this struct.
127
+
u32;
128
+
if (DecodePointers) {Chunk64 *FrameTable: u64;} else {u64 FrameTableOffset;} // File offset of ChunkMXJVFT64.
129
+
u64 VideoFrames; // The total number of VFTE entries (These point to MXJVVF64 chunks that contain images). It's possible that several VFTE entries point to the same MXJVVF64 chunk.
130
+
u32 MaxReadSize; // Guess: Seems to be the max of all video and audio frame chunk pairs. Perhaps to tell any software what the max. buffer size needs to be.
131
+
u32;
132
+
u64;
133
+
u64;
134
+
u32 FrameWidth;
135
+
u32 FrameHeight;
136
+
u32 FrameWidth2; // Maybe needed when the video is anamorphic? It's the same as the above width in all my test files.
137
+
u32 FrameHeight2; // Maybe needed when the video is anamorphic? It's the same as the above height in all my test files.
138
+
u32;
139
+
u32 MaxJPEGSize; // The JPEG data size of the largest MXJVVF64 chunk. (The size only includes the JPEG data)
140
+
u64 AudioFrames; // Number of AFTE entries (These point to MXJVAF64 chunks that contain waveform data)
141
+
u64 MaxAudioChunkSize; // The size of the largest MXJVAF64 chunk. (The size includes the chunk identifier and length field and all its data)
142
+
u8 Unknown8[16]; // Guess: This could be audio related stuff.
143
+
u64 AudioSamples; // Total number of audio samples.
144
+
};
145
+
146
+
struct ChunkMXJVHD64 {
147
+
u32;
148
+
u32;
149
+
if (DecodePointers) {Chunk64 *FrameTable: u64;} else {u64 FrameTableOffset;}
0 commit comments