영상에서 썸네일을 자동으로 추출하여, 썸네일을 만들거나 이미지 파일을 분석하는 방법을 활용할 수 있을 것이다. 썸네일의 용도보다는 주기적으로 영상에 이미지를 추출하여 사진을 분석하는 용도로 사용하기 위해서 구글링을 하게 되었다.
다양한 방법이 있고, 라이브러리마다 성능의 차이는 있을 수 있다. 예를 들어 좀 더 복잡한 방식은 더 높은 성능을 자랑할 수 있다. 단순한 라이브러리는 상대적으로 낮은 성능(ex: 추출 속도)을 보여줄 수 있지만 이미지를 수집하는데 큰 지장이 없기에 이번에는 쉬운 방법의 썸네일을 추출하는 라이브러리를 소개하고자 한다.
😎Maven 설정
Java 기반이며 필자는 Maven 기반으로 프로젝트를 생성하였다. 라이브러리는 "jcodec"이라는 라이브러리를 활용하였는데 아래 2개의 Dependency를 추가하면 된다.
<dependency>
<groupId>org.jcodec</groupId>
<artifactId>jcodec</artifactId>
<version>0.2.3</version>
</dependency>
<dependency>
<groupId>org.jcodec</groupId>
<artifactId>jcodec-javase</artifactId>
<version>0.2.3</version>
</dependency>
😎 jcodec의 Support 정보
jcodec은 다음과 같은 비디오와 오디오, 포맷등을 지원한다
Video Codecs
H.264 main profile decoder;
H.264 baseline profile encoder;
VP8 decoder (I frames only);
VP8 encoder (I frames only);
MPEG 1/2 decoder ( I/P/B frames, interlace );
Apple ProRes decoder/encoder;
JPEG decoder;
PNG decoder/encoder.
DivX/Xvid
Audio Codecs
SMPTE 302M decoder;
AAC decoder (JAAD)
RAW PCM.
Formats
MP4 ( MOV ) demuxer / muxer;
MKV ( Matroska ) demuxer / muxer;
MPEG PS demuxer;
MPEG TS demuxer;
WAV demuxer/muxer;
MPEG Audio (MP3) demuxer;
ADTS demuxer.DPX parser
대부분의 동영상을 지원한다고 봐도 무방할 것 같다.
😎 Source 및 설명
main.java
import java.io.File;
public class Main {
public static void main(String[] args) throws Exception {
Mp4Test mp4Test = new Mp4Test();
File source = new File(파일경로);
long startTime = System.currentTimeMillis();
mp4Test.getThumbnail(source);
long endTime = System.currentTimeMillis();
System.out.println((endTime-startTime) + "(ms)");
}
}
파일경로 부분은 절대경로를 입력한다. 예를 들어 C:/Test 폴더에 a.mp4 라는 비디오의 이미지를 캡쳐하고 싶으면, "C:/Test/a.mp4" 라고 입력을 한다.
Mp4Test.java
import java.io.File;
import java.io.IOException;
import org.jcodec.api.JCodecException;
public class Mp4Test {
/**
* 썸네일을 추출하는 메소드
*
* @param source mp4 file.
* @param thumbnail
* @return
* @throws IOException
* @throws JCodecException
* @throws InterruptedException
*/
public void getThumbnail(File source) throws Exception {
double plusSize = 0.5;
int threadSize = 8;
VideoThread[] videoThread = new VideoThread[threadSize];
for(int i = 0; i < videoThread.length; i++) {
videoThread[i] = new VideoThread(source, threadSize, i, plusSize);
videoThread[i].start();
}
boolean runFlag = true;
while(runFlag) {
Thread.sleep(1000);
runFlag = false;
for(int i = 0; i < threadSize; i++) {
if(videoThread[i].isAlive())
runFlag = true;
}
}
}
}
필자의 설정은 0.5초마다 이미지를 추출하는 방식이다. 그리고 속도를 높이기 위해서 스레스(Thread)를 사용하였는데 정확한 시간(총 걸린시간)을 측정하기 위해서 스레드가 모두 종료가 되야지 해당 메소드가 종료되게 만들었다.
VideoThread.java
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import org.jcodec.api.FrameGrab;
import org.jcodec.common.io.NIOUtils;
import org.jcodec.common.model.Picture;
import org.jcodec.scale.AWTUtil;
public class VideoThread extends Thread {
private int threadNo;
private int threadSize;
private double plusSize;
private File source;
public VideoThread(File source, int threadSize, int threadNo, double plusSize) {
this.source = source;
this.threadSize = threadSize;
this.threadNo = threadNo;
this.plusSize = plusSize;
}
public void run() {
FrameGrab grab;
try {
grab = FrameGrab.createFrameGrab(NIOUtils.readableChannel(source));
for(int m = 0; m < 120; m++) {
if(m % threadSize == threadNo) {
double startSec = m * plusSize;
System.out.println(threadNo + " " + startSec);
int frameCount = 1;
grab.seekToSecondPrecise(startSec);
for (int i=0; i < frameCount; i++) {
Picture picture = grab.getNativeFrame();
//for JDK (jcodec-javase)
BufferedImage bufferedImage = AWTUtil.toBufferedImage(picture);
ImageIO.write(bufferedImage, "png",
new File("E:/Project/steel/image/frame" + m + ".png"));
}
}
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
실질적으로 라이브러리를 호출하여 작동을 하는 클래스가 바로 VideoThread.java이다. 이미지를 추출하면, png 포맷으로 파일을 저장하게 되어 있는 구조이다.
실행결과
![](https://blog.kakaocdn.net/dn/cfS03N/btrlTlpm3sL/7iBW9euTlpEyRM5F6eAG41/img.png)
필자 컴퓨터 Core가 8개 이고, Thread를 8로 설정하였기 때문에 CPU를 Full로 사용하는 것을 볼 수 있다. 1분정도 되는 영상을 데탑 8코어 Cpu로 120장을 추출하는데
37815(ms)
약 37초 정도가 걸린 것을 확인할 수 있다.
Jcodec에 관련된 설명은 github에서 확인하여 필요한 부분을 직접 코딩하는 것을 권유드린다.
'Back-end > JAVA & Spring' 카테고리의 다른 글
[JAVA] FFmpeg로 동영상 재생 시간 추출하기(WINDOW) (0) | 2021.11.24 |
---|---|
[Java] 파일에서 확장자(File extension) 얻는 방법 (0) | 2021.11.23 |
[JAVA] image resize & crop (Thumbnail) (0) | 2021.11.23 |
[JAVA] 특정 폴더에 있는 파일 읽기 (0) | 2021.11.19 |
[JAVA] JSONObject key 값이 null 일때 해결 방법 (0) | 2021.11.15 |
댓글