ffmpeg_alac_mp3.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. "git.wanpinghui.com/WPH/go_common/wph"
  6. "os"
  7. "os/exec"
  8. "path"
  9. "path/filepath"
  10. "strings"
  11. )
  12. func main() {
  13. inputFiles, err := listFiles(`./ffmpeg/mp3`, `.mp3`)
  14. if nil != err {
  15. println(`查找输入文件出错:`, err.Error())
  16. }
  17. if nil == inputFiles || len(inputFiles) == 0 {
  18. return
  19. }
  20. var command, out string
  21. for _, f := range inputFiles {
  22. o := fmt.Sprintf(`./ffmpeg/output/%s.m4a`, strings.TrimRight(strings.ToLower(path.Base(f)), ".mp3"))
  23. command, out, err = MP3ToM4A(f, o)
  24. if nil != err {
  25. println("error:", err.Error())
  26. println("command:", command)
  27. println("out:\n", out)
  28. }
  29. }
  30. }
  31. const (
  32. wrongMP3Output = `Estimating duration from bitrate, this may be inaccurate`
  33. infoCmdFormat = `ffmpeg -i %s`
  34. tempCmdFormat = `ffmpeg -i %s -c:a alac -b:a 80k -c:v copy %s -y`
  35. audioCmdFormat = `ffmpeg -i %s -movflags faststart -c:a aac -b:a 80k -vn %s -y`
  36. transCmdFormat = `ffmpeg -i %s -movflags faststart -c:a aac -b:a 80k %s -y`
  37. )
  38. // mp3转m4a
  39. func MP3ToM4A(inputFileName, outputFileName string) (string, string, error) {
  40. var err error
  41. var command string
  42. // 先查看文件信息
  43. command = fmt.Sprintf(infoCmdFormat, inputFileName)
  44. out, _ := RunCmd(command)
  45. if strings.Contains(out, wrongMP3Output) { // 处理特殊编码的mp3文件
  46. // 选用原始编码器先复写一份临时m4a,此文件含图像,体积特别大
  47. tempFileName := fmt.Sprintf(`./%d.m4a`, wph.NextId())
  48. command = fmt.Sprintf(tempCmdFormat, inputFileName, tempFileName)
  49. out, err = RunCmd(command)
  50. if nil != err {
  51. return command, out, err
  52. }
  53. // 从临时文件中提取音频
  54. command = fmt.Sprintf(audioCmdFormat, tempFileName, outputFileName)
  55. out, err = RunCmd(command)
  56. if nil != err {
  57. return command, out, err
  58. }
  59. // 删除临时文件
  60. _ = os.Remove(tempFileName)
  61. } else { // 正常编码的mp3
  62. command := fmt.Sprintf(transCmdFormat, inputFileName, outputFileName)
  63. out, err = RunCmd(command)
  64. if nil != err {
  65. return command, out, err
  66. }
  67. }
  68. return command, out, nil
  69. }
  70. func RunCmd(command string) (string, error) {
  71. command = strings.TrimSpace(command)
  72. if command == "" {
  73. return "", nil
  74. }
  75. var cmdAndArgs []string
  76. arr := strings.Split(command, " ")
  77. for i := 0; i < len(arr); i++ {
  78. part := strings.TrimSpace(arr[i])
  79. if part == "" {
  80. continue
  81. }
  82. cmdAndArgs = append(cmdAndArgs, part)
  83. }
  84. if nil == cmdAndArgs || len(cmdAndArgs) == 0 {
  85. return "", nil
  86. }
  87. var cmd *exec.Cmd
  88. if len(cmdAndArgs) == 1 {
  89. cmd = exec.Command(cmdAndArgs[0])
  90. } else {
  91. cmd = exec.Command(cmdAndArgs[0], cmdAndArgs[1:]...)
  92. }
  93. var out bytes.Buffer
  94. cmd.Stdout = &out
  95. cmd.Stderr = &out
  96. err := cmd.Start()
  97. if nil != err {
  98. return out.String(), err
  99. }
  100. err = cmd.Wait()
  101. return out.String(), err
  102. }
  103. func listFiles(dirPath string, extList ...string) ([]string, error) {
  104. dir, err := os.Stat(dirPath)
  105. if (nil != err && os.IsNotExist(err)) || !dir.IsDir() {
  106. return nil, nil
  107. }
  108. err = nil
  109. var files []string
  110. err = filepath.Walk(dirPath, func(name string, info os.FileInfo, err error) error {
  111. if info.IsDir() {
  112. return nil
  113. }
  114. ext := strings.ToLower(path.Ext(name))
  115. if wph.Contains(extList, ext) {
  116. files = append(files, name)
  117. }
  118. return nil
  119. })
  120. if nil != err {
  121. return nil, err
  122. }
  123. return files, nil
  124. }