Skip to content

Commit 32c9056

Browse files
committed
Make use of the new MXRIFF64 package
- Remove old mxv-chunk stuff - Rewrite demux-file.go to use the new parser - Update README.md
1 parent 1643d85 commit 32c9056

5 files changed

Lines changed: 57 additions & 396 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ A detailed explanation is given below.
1212

1313
I tested this tool on video material from:
1414

15-
- MAGIX Video Deluxe 2007/2008
15+
- MAGIX Video deluxe 2007/2008
1616
- MAGIX Video Pro X5
17+
- MAGIX Video deluxe 2025
1718

1819
## Reason for its existence
1920

demux-file.go

Lines changed: 55 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2022 David Vogel
1+
// Copyright (c) 2022-2025 David Vogel
22
//
33
// This software is released under the MIT License.
44
// https://opensource.org/licenses/MIT
@@ -7,10 +7,12 @@ package main
77

88
import (
99
"fmt"
10+
"io"
1011
"log"
1112
"os"
1213
"path/filepath"
1314

15+
"github.com/Dadido3/mxv-demuxer/mxv"
1416
"github.com/moutend/go-wav"
1517
)
1618

@@ -22,34 +24,13 @@ func demuxFile(filename string) error {
2224
return fmt.Errorf("failed to open file: %w", err)
2325
}
2426

25-
chunk, err := ParseChunk64(file)
27+
mxvReader, err := mxv.NewReader(file)
2628
if err != nil {
27-
return fmt.Errorf("failed to parse root chunk: %w", err)
29+
return fmt.Errorf("failed to read MXV file: %w", err)
2830
}
2931

30-
chunkMXRIFF64, ok := chunk.(*ChunkMXRIFF64)
31-
if !ok {
32-
return fmt.Errorf("file doesn't contain a MXRIFF64 as root chunk")
33-
}
34-
35-
// Get wave format.
36-
var audioSampleRate, audioBitDepth, audioChannels int
37-
var wavObject *wav.File
38-
for _, childChunk := range chunkMXRIFF64.Chunks {
39-
if wfmtChunk, ok := childChunk.(*ChunkMXWFMT64); ok {
40-
audioSampleRate = int(wfmtChunk.ByteRate) / int(wfmtChunk.BytesPerSample) // Seems to be more reliable than just using the SampleRate field.
41-
audioBitDepth = int(wfmtChunk.ChannelBitDepth)
42-
audioChannels = int(wfmtChunk.Channels)
43-
log.Printf("Found waveform table chunk: %v", wfmtChunk)
44-
log.Printf("Set up audio: SampleRate = %d, BitDepth = %d, Channels = %d", audioSampleRate, audioBitDepth, audioChannels)
45-
46-
// Set up empty wav object.
47-
if wavObject, err = wav.New(audioSampleRate, audioBitDepth, audioChannels); err != nil {
48-
return fmt.Errorf("failed to create wav object: %w", err)
49-
}
50-
51-
break
52-
}
32+
if err := mxvReader.PrepareLookupTable(); err != nil {
33+
return fmt.Errorf("failed to prepare lookup table: %w", err)
5334
}
5435

5536
// Create output directory.
@@ -59,54 +40,67 @@ func demuxFile(filename string) error {
5940
return fmt.Errorf("failed to create output directory: %w", err)
6041
}
6142

62-
// Get MXLIST64 with audio and video frames (MXJVFL64).
63-
var frameCounter, audioSampleCounter int
64-
for _, childChunk := range chunkMXRIFF64.Chunks {
65-
if listChunk, ok := childChunk.(*ChunkMXLIST64); ok && listChunk.ContentType == MXJVFL64 {
66-
67-
// Go through list of video and audio frames.
68-
for _, frameChunk := range listChunk.Chunks {
69-
switch frameChunk := frameChunk.(type) {
70-
case *ChunkMXJVVF64:
71-
// Create file and write image data into it.
72-
videoFilename := filepath.Join(outputPath, fmt.Sprintf("video-%06d.jpeg", frameCounter))
73-
frameCounter++
74-
75-
if err := os.WriteFile(videoFilename, frameChunk.JPEGData, 0666); err != nil {
76-
return err
77-
}
78-
79-
case *ChunkMXJVAF64:
80-
// Write audio data into wave object.
81-
if wavObject != nil {
82-
if _, err := wavObject.Write(frameChunk.Data); err != nil {
83-
return err
84-
}
85-
audioSampleCounter += int(frameChunk.Samples)
86-
} else {
87-
log.Printf("Found audio chunk, but there was no waveform table chunk.")
88-
}
89-
90-
}
91-
}
43+
log.Printf("MXV info: %+v.", mxvReader.Info)
9244

93-
break
45+
// Video frames.
46+
log.Printf("Extracting video frames.")
47+
for frame := range mxvReader.VideoFrames() {
48+
videoFilename := filepath.Join(outputPath, fmt.Sprintf("video-%06d.jpeg", frame))
49+
file, err := os.Create(videoFilename)
50+
if err != nil {
51+
return fmt.Errorf("failed to create file: %w", err)
52+
}
53+
frameReader, err := mxvReader.VideoFrameData(frame)
54+
if err != nil {
55+
return fmt.Errorf("failed to get video data stream: %w", err)
56+
}
57+
if _, err := io.Copy(file, frameReader); err != nil {
58+
return fmt.Errorf("failed to copy video data stream: %w", err)
9459
}
9560
}
9661

97-
// Write wav data into file.
98-
if wavObject != nil {
62+
log.Printf("Finished extracting video frames.")
63+
64+
if mxvReader.Info.HasAudio {
65+
// TODO: go-wav doesn't support streaming, therefore replace it
66+
67+
// Set up empty wav object.
68+
wavObject, err := wav.New(int(mxvReader.Info.AudioSampleRate), int(mxvReader.Info.AudioChannelBitDepth), int(mxvReader.Info.AudioChannels))
69+
if err != nil {
70+
return fmt.Errorf("failed to create wav object: %w", err)
71+
}
72+
73+
// Append sample data.
74+
log.Printf("Extracting audio samples.")
75+
for frame := range mxvReader.AudioFrames() {
76+
frameReader, _, _, err := mxvReader.AudioFrameData(frame)
77+
if err != nil {
78+
return fmt.Errorf("failed to get audio data stream: %w", err)
79+
}
80+
frameData, err := io.ReadAll(frameReader)
81+
if err != nil {
82+
return fmt.Errorf("failed to read audio data stream: %w", err)
83+
}
84+
if _, err := wavObject.Write(frameData); err != nil {
85+
return fmt.Errorf("failed to append audio data to wave object: %w", err)
86+
}
87+
}
88+
89+
// Write audio file to disk.
90+
audioFilename := filepath.Join(outputPath, "audio.wav")
91+
log.Printf("Writing extracted audio data to disk at %q.", audioFilename)
9992
wavTemp, err := wav.Marshal(wavObject)
10093
if err != nil {
10194
return fmt.Errorf("failed to encode wave data: %w", err)
10295
}
103-
audioFilename := filepath.Join(outputPath, "audio.wav")
10496
if err := os.WriteFile(audioFilename, wavTemp, 0666); err != nil {
10597
return fmt.Errorf("failed to write audio file: %w", err)
10698
}
99+
100+
log.Printf("Finished writing audio data.")
107101
}
108102

109-
log.Printf("Completely demuxed %q: %d video frames, %d audio samples", filename, frameCounter, audioSampleCounter)
103+
log.Printf("Completely demuxed %q.", filename)
110104

111105
return nil
112106
}

main.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package main
77

88
import (
99
"flag"
10-
"fmt"
1110
"io/ioutil"
1211
"log"
1312
"path/filepath"
@@ -36,11 +35,6 @@ func main() {
3635
log.Printf("Failed to demux %q: %v", filename, err)
3736
}
3837
}
39-
40-
log.Printf("All process done.")
41-
42-
log.Printf("Press any key to exit...")
43-
fmt.Scanln()
4438
}
4539

4640
func findFiles(root string) ([]string, error) {

0 commit comments

Comments
 (0)