SpringBoot + FFmpeg 사용

공부는 혼자하는 거·2023년 2월 14일
0

Spring Tip

목록 보기
35/52

서론

파일을 변환해서 외부 api 에게 넘겨줘야 하는 일을 맡았다. 간략하게 이야기하자면, mp4 파일 중에서 오디오 소스만 추출해서 wav 파일로 만들고, 이 wav 파일을 외부 API 에게 넘겨주고 반환받은 Byte array를 다시 wav 파일로 만든 다음, 다른 mp4 파일에 인코딩하는 일이었다. 하나의 트랜잭션 안에 파일 4개를 디스크에 쓰고 지워야 하는 하드한 I/O 작업을 요구하는 일이었다. 처음에는 자바 native 코드로 해결할 수 있는 방법이 있을까 고민을 했으나, 내가 검색을 못하는지, JVM 환경에서 직접적으로 파일을 조작하고, 추출하는 방법을 찾지는 못했다. 그러다 이런 상황에서 유용하게 쓰이는 유용한 프레임워크를 하나 발견했다.

ffmpeg

ffmpeg는 오픈소스이면서, 비디오/오디오 관련한 많은 기능을 제공하고 있으며, 성능또한 상당히 좋은 편이라고 한다. CLI 를 지원하므로, 이걸 이용해서, JAVA의 ProcessBuilder를 활용하여 명령을 전달할 생각이었으나, 이 CLI를 Wrapping한 라이브러리가 존재했다.

    implementation("net.bramp.ffmpeg:ffmpeg:0.7.0")

당근 먼저 FFMPEG를 설치해줘야 한다. 운영체제마다 설치경로가 다르므로, yml에 경로를 명시해주고, @Value로 inject 받아 활용했다.


ffmpeg:
  mpeg: /opt/homebrew/bin/ffmpeg
  probe: /opt/homebrew/bin/ffprobe
  savePath: /Users/stella/Desktop/company/codework/api/src/main/resources/static/file/
@Configuration
class FFmpegConfig {


    private val log = KotlinLogging.logger { }

    @Value("\${ffmpeg.mpeg}")
    private lateinit var ffmpegLocation: String

    @Value("\${ffmpeg.probe}")
    private lateinit var ffprobeLocation: String


    @Bean(name = ["ffMpeg"])
    fun ffMpeg(): FFmpeg {
        log.info { "just one init ffMpeg, its bytebuddy magic!" }
        return FFmpeg(ffmpegLocation)
    }

    @Bean(name = ["ffProbe"])
    fun ffProbe(): FFprobe {
        log.info { "just one init ffProbe, its bytebuddy magic!" }
        return FFprobe(ffprobeLocation)
    }

    @Bean
    fun ffExecutor(ffMpeg: FFmpeg, ffProbe: FFprobe): FFmpegExecutor {
        return FFmpegExecutor(ffMpeg, ffProbe)
    }

    @Value("\${ffmpeg.savePath}")
    fun setNameStatic(ffmpegSavePath: String) {
        savePath = ffmpegSavePath
    }

    companion object {
        var savePath: String = ""

    }

}

사용법은 아주 간단하다. 간단하게 mp4 파일을 wav 파일로 변환하는 테스트 코드를 작성했다.

    @Test
    fun convertVideoTest() {

        val inputPath = "/Users/stella/Desktop/company/codework/back/src/test/resources/video/testvideo.mp4"
        val outputPath  = "/Users/stella/Desktop/company/codework/back/src/test/resources/video"

        val fFmpeg = FFmpeg("/opt/homebrew/bin/ffmpeg")
        val fFprobe = FFprobe("/opt/homebrew/bin/ffprobe")

        //ffmpeg -i <infile> -ac 2 -f wav <outfile>

        val builder: FFmpegBuilder = FFmpegBuilder()
            .overrideOutputFiles(true)
            .setInput(inputPath)
            .addOutput(outputPath + "/new.wav")
            .addExtraArgs("-ac","2")
            .addExtraArgs("-f","wav")
            .done()

        val excutor = FFmpegExecutor(fFmpeg, fFprobe)
        excutor.createJob(builder) { p ->
            if (p.isEnd()) {
                println("make success")
            }
        }.run()

        val file1 = File(outputPath + "/new.wav")
        println(file1.name)
    }

참고

https://hanburn.tistory.com/175
https://superuser.com/questions/1137612/ffmpeg-replace-audio-in-video
https://islet4you.tistory.com/entry/Java-FFmpeg-%EB%A5%BC-%ED%86%B5%ED%95%9C-%EC%98%81%EC%83%81-%EB%8B%A4%EB%A3%A8%EA%B8%B0-chapter01

profile
시간대비효율

0개의 댓글