Skip to content

Commit

Permalink
Copy non-mp4-compatible files instead of encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
naftalibeder committed Aug 17, 2024
1 parent 854172c commit 68bbc4d
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 43 deletions.
15 changes: 7 additions & 8 deletions detaku/analyzeDir.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,6 @@ func analyzeDir(srcDir string) (AnalyzeDirResult, error) {
vidFileInfoMap := types.FileInfoMap{}
vidExtCtMap := types.ExtCtMap{}
vidTotalDurationSec := 0
vidTotalDuration := ""
vidsNeedReEncodeCt := 0

// A lookup table recording the existence of each supplementary json file.
// Each file is keyed by its full path.
Expand All @@ -128,11 +126,6 @@ func analyzeDir(srcDir string) (AnalyzeDirResult, error) {
vidFileInfoMap[result.Path] = result.MediaFileInfo
vidExtCtMap[result.Ext]++
vidTotalDurationSec += int(result.MediaFileInfo.VidInfo.DurationSec)
dur, _ := time.ParseDuration(fmt.Sprintf("%ds", vidTotalDurationSec))
vidTotalDuration = dur.String()
if result.MediaFileInfo.VidInfo.NeedsReEncode {
vidsNeedReEncodeCt++
}
}
supplFileInfoMap[result.Path] = result.SupplFileInfo

Expand All @@ -150,10 +143,16 @@ func analyzeDir(srcDir string) (AnalyzeDirResult, error) {
vidExtsDisp = fmt.Sprintf("(%s)", vidExtsSorted)
}

vidTotalDurationDisp := ""
if vidTotalDurationSec > 0 {
d, _ := time.ParseDuration(fmt.Sprintf("%ds", vidTotalDurationSec))
vidTotalDurationDisp = fmt.Sprintf("(%s)", d)
}

console.Update(console.PhaseAnalyzing, [][]string{
{"", fmt.Sprintf("- Analyzed %d/%d files", walkedFileCt, totalFileCt)},
{"", fmt.Sprintf("- Images: %d %s", len(imgFileInfoMap), imgExtsDisp)},
{"", fmt.Sprintf("- Videos: %d %s (%s, %d need re-encoding)", len(vidFileInfoMap), vidExtsDisp, vidTotalDuration, vidsNeedReEncodeCt)},
{"", fmt.Sprintf("- Videos: %d %s %s", len(vidFileInfoMap), vidExtsDisp, vidTotalDurationDisp)},
{"", fmt.Sprintf("- Supplementary files: %d", len(supplFileInfoMap))},
{"", "- " + console.GetElapsedStr(sectionStart) + " elapsed"},
})
Expand Down
6 changes: 4 additions & 2 deletions detaku/convertFile.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ func convertFile(job ConvertFileJob) (result ConvertFileResult) {
if !foundDate {
canSaveFile = false
logEntry.Errors = append(logEntry.Errors, "No earliest date found in file, supplementary file, or filename")
} else {
logEntry.UsedDateTag = earliestDateTag
}

// Find all geo tags.
Expand Down Expand Up @@ -194,11 +196,11 @@ func convertFile(job ConvertFileJob) (result ConvertFileResult) {
tmpPath = tmpPathNext
}

// Normalize a video by copying or re-encoding.
// Normalize a video by repackaging or copying.

tmpPathNext = ""
if fileInfo.MediaKind == types.Video {
tmpPathNext, err = encode.CopyOrEncodeVideo(fileInfo, tmpPath, tmpWorkingDir, "3")
tmpPathNext, err = encode.CopyVideo(fileInfo, tmpPath, tmpWorkingDir, "3")
if err != nil {
canSaveFile = false
logEntry.Errors = append(logEntry.Errors, fmt.Sprintf("Error copying or encoding video: %s", err))
Expand Down
46 changes: 20 additions & 26 deletions encode/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,31 @@ import (
"golang.org/x/exp/slices"
)

func CopyOrEncodeVideo(fileInfo types.FileInfo, srcPath string, tmpDir string, fileNameNoExt string) (destPath string, err error) {
func CopyVideo(fileInfo types.FileInfo, srcPath string, tmpDir string, fileNameNoExt string) (destPath string, err error) {
if fileInfo.MediaKind != types.Video {
return "", errors.New("file is not a video")
}

// Copy or encode video and audio with ffmpeg.
// Repackage the video and audio in an mp4 container if possible, or just
// duplicate the file.

vidInfo := fileInfo.VidInfo
cmdArgs := []string{
"-i", srcPath,
"-f", "mp4",
}

if !vidInfo.NeedsReEncode {
cmdArgs = append(cmdArgs,
var cmd *exec.Cmd
if fileInfo.VidInfo.CanBeRePackagedInMP4 {
destPath = filepath.Join(tmpDir, fileNameNoExt) + ".mp4"
cmdArgs := []string{
"-i", srcPath,
"-f", "mp4",
"-c:v", "copy",
"-c:a", "copy",
)
destPath,
}
cmd = exec.Command(lib.FfmpegBin, cmdArgs...)
} else {
cmdArgs = append(cmdArgs,
"-c:v", "libx264",
"-pix_fmt", "yuv420p",
"-c:a", "aac",
"-b:a", "128k",
"-preset", "slow",
"-crf", "17",
)
ext := filepath.Ext(fileInfo.Name)
destPath = filepath.Join(tmpDir, fileNameNoExt) + ext
cmd = exec.Command("cp", srcPath, destPath)
}

destPath = filepath.Join(tmpDir, fileNameNoExt) + ".mp4"
cmdArgs = append(cmdArgs, destPath)
cmd := exec.Command((lib.FfmpegBin), cmdArgs...)

out, err := cmd.CombinedOutput()
if err != nil {
return "", errors.Join(err, fmt.Errorf(string(out)))
Expand Down Expand Up @@ -106,10 +98,12 @@ func GetVidInfo(srcPath string) (vidInfo types.VidInfo, err error) {
vidInfo.AudCodec,
)

// Determine if file can simply be repackaged.
// Determine if file can simply be repackaged. (If not, putting it into an
// mp4 container would require re-encoding, which is less desirable than
// preserving the file as-is.)

if !vidInfo.IsVidCompat || !vidInfo.IsAudCompat {
vidInfo.NeedsReEncode = true
if vidInfo.IsVidCompat && vidInfo.IsAudCompat {
vidInfo.CanBeRePackagedInMP4 = true
}

// Get video duration.
Expand Down
1 change: 1 addition & 0 deletions log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type LogEntry struct {
DateSrc DateSrc
DateSrcExifTagName string
DateSrcImgTitleSearchStr string
UsedDateTag types.ExifDateTag
AllExifTags types.ExifTags
SupplExifTags types.ExifTags
VidInfo types.VidInfo
Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Detaku uses each file's original metadata, any related metadata file, and the fi
- Copies geolocation data, if needed, from any related metadata file.
- File quality
- Edits image exif data without recompressing files.
- Edits video exif data and attempts to repackage as `.mp4` without re-encoding.
- Edits video exif data and attempts to repackage as `.mp4` without re-encoding, for compatibility. Otherwise, simply renames and copies the file.
- Fixes incorrect extensions based on the actual file data.
- Preserves original filename in the output filename and exif title tag.
- Copies files to an output directory, instead of modifying in-place.
Expand Down
12 changes: 6 additions & 6 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ type ExifDateTag struct {
}

type VidInfo struct {
VidCodec string
IsVidCompat bool
AudCodec string
IsAudCompat bool
NeedsReEncode bool
DurationSec float64
VidCodec string
IsVidCompat bool
AudCodec string
IsAudCompat bool
CanBeRePackagedInMP4 bool
DurationSec float64
}

// Results.
Expand Down

0 comments on commit 68bbc4d

Please sign in to comment.