웹모아
웹모아[손님] 검색   로그인    


 
이미지
 


ffmpeg로 동영상에서 jpg 이미지 추출방법
  2012-07-16 21:05:27 댓글:(0)   조회:4719




ffmpeg로 동영상에서 jpg 이미지 추출하기


출처와 다운로드 & 참고블로그

ffmpeg 홈페이지: http://ffmpeg.org/download.html

mediainfo 출처: http://mediainfo.sourceforge.net/ko

Command Line Calculator : http://cmdlinecalc.sourceforge.net/

썸네일 추출 참고: http://naingyo.springnote.com/pages/1561700

배치파일 문법 참고: http://snoopybox.co.kr/1404


목차

1. 목적

2. 사용방법

3. 배치파일 내용

4. ffmpeg 옵션 설명

5. 다른방법(1)(2)(3)



1. 목적


ffmpeg로 flv 동영상 전체 구간에서 고르게 원하는 장 수 만큼의 이미지를 추출하는 게 목적입니다.

검색해 보니 이미지 추출하는 방법은 다른 블로그에 많이 있긴합니다만 제가 원하는 형태는 없어서 고안해 본 것입니다.

ffmpeg, Command Line Calculator(커맨드 라인 계산기), mediainfo 32bit CLI(미디어인포) 를 사용해서 배치 파일을 만들었습니다.

이 방법 외에도 이미지 추출 프로그램(이미지딱 같은)이나 KMPlayer의 고급캡처 기능 등 방법은 많이 있습니다.


프로그래밍 언어 다 놔두고 굳이 배치파일로 만든이유는 쉬울줄 알았는데 해보니 잘 안되서 그만 오기로 하고 말았습니다.......

배치파일 알고보니 심오합니다.



2. 사용방법


먼저 제 컴퓨터 환경은 windows XP 서비스팩3입니다. 다르면 안 될 수도 있겠죠.

구성: 배치파일, ffmpeg.exe(git-ceb0dd9-win32-static), calc.exe, MediaInfo.exe, MediaInfo.dll 이 모두 있어야 합니다.

(첨부파일 안에 모두 있습니다.)


Thumbnail.exe


제가 쓰는 배치파일을 첨부해 놓았습니다. 압축을 풀고(더블클릭) 그 폴더 안에 flv 파일을 1개만 놓고 flv스샷.bat 를 실행하면

파일이름_thumbnail 이란 폴더를 만들고 그 안에 01.jpg, 파일이름_02.jpg....... 이런식으로 이미지 파일을 뽑습니다.

폴더 안에 flv파일이 동시에 여러개 있으면 제대로 추출이 안됩니다. 그리고 파일명에 공백이 있어서도 안됩니다.

이런 부분들은 배치파일을 다루는 제 능력이 부족해서 해결을 못했습니다.

제가 쓰기 편하게 만들어 놓은 것일 뿐이라, 다목적용이 아닙니다. 사용목적에 따라 옵션을 바꿔야 할 겁니다.

crop의 경우 배치파일에 넣지 않았지만, -vf crop=<width>:<height>:<X>:<Y> 형식으로 추가하면 같이 쓸 수 있습니다.


flv스샷1.bat는 동영상전체구간에서 스샷장수만 변경할 수 있습니다. -vf thumbnail필터를 사용해 대표이미지를 뽑습니다.

              필터로 인해 이미지 추출간격은 프레임레이트*2 입니다.(대략2초) 동영상 재생시간을 고려해서 스샷 장 수를 결정하세요.

              영상길이는 짧은데 수십장씩 추출하고 싶다면 flv스샷2.bat를 쓰세요.

flv스샷2.bat는, 스샷장수, 이미지 품질, 추출해상도, 추출시작시간, 추출종료시간을 지정할 수 있도록 해놓은 것입니다.

              -thumbnail 필터는 사용하지 않았습니다. 그래서 영상추출간격은 대충 0.03초 이상이면 충분한것 같습니다.

              쓰고싶다면 직접 배치파일에  -vf thumbnail을 추가하시면 됩니다.(추가 위치는 flv스샷1.bat를 참고하면 쉽게 알 수 있습니다)


flv 파일만이 아니라 배치파일의 내용을 바꾸면 다른 동영상 포맷도 추출가능합니다. 메모장으로 열고 메뉴의 바꾸기에서 flv 문자를 원하는 형식의 문자열로 모두 바꾸면 됩니다.

codec ID: wmv3 의 경우 일부 이미지가 깨져서 나오는 경우가 있습니다. Mp4로 인코딩해서 뽑으면 잘 나오는걸로 봐서 파일문제가 아니라

일부 코덱중 잘 안되는 경우가 있는 걸로 보입니다.


또 배치파일 내에서 ffmpeg의 옵션을 조정하면, jpg가 아닌 png나 bmp도로 추출 가능합니다. gif는 안해봤습니다.

썸네일 용이 아닌 상당히 짧은 시간간격에서 프레임을 추출해서 짤방같은 걸 만들 목적이면 이 배치파일말고 아래쪽의 5.다른방법을 참고하시면 됩니다. 해보고 에러, 이상현상 등으로 안되는 분은 다른 방법을 찾으세요. 저는 해결할 능력이 없습니다.




3. 배치파일 내용(flv스샷1.bat)


쓸데없이 길지만 원리는 무척 단순합니다. ffmpeg를 쓰는 건 간단한데, 좀 편하게 쓰려고 다른 걸 추가하니 배보다 배꼽이 더 큽니다.

ffmpeg를 이용해서 0초에서(정확히는 썸네일필터에 의해 대표이미지가 나올 때입니다) 프레임을 1장 추출

그 다음에 시간을 바꾸고 다시 1장 추출, 이 과정을 원하는 스샷수 만큼 반복입니다.


@echo off 

pushd %~dp0         명령이 실행되는 위치를 현재 폴더로 합니다.


for %%A in (*.flv) do mediainfo --Inform=General;%%Duration%% "%%~nA.flv" > tmpfile   mediainfo로 총재생시간을  임시파일에 저장

for /f "tokens=*" %%a in ('type tmpfile') do set dura=%%a                    임시파일에 저장된 값을 읽어 dura 라는 변수에 저장합니다.

for %%B in (*.flv) do mediainfo --Inform=Video;%%FrameCount%% "%%~nB.flv" > tmpfile   mediainfo로 총프레임수를 임시파일에 저장

for /f "tokens=*" %%b in ('type tmpfile') do set frameC=%%b                 임시파일에 저장된 값을 읽어 frameC이란 변수에 저장합니다.

for %%C in (*.flv) do mediainfo --Inform=Video;%%FrameRate%% "%%~nC.flv" > tmpfile   mediainfo로 프레임레이트를 임시파일에 저장

for /f "tokens=*" %%c in ('type tmpfile') do set frameR=%%c                  임시파일에 저장된 값을 읽어 frameR이란 변수에 저장합니다.


calc %dura%/1000>tmpfile                 ms 단위를 보기편한 초 단위로 바꿉니다.

set /p secTime=<tmpfile                    임시파일값을 secTime이란 변수에 저장합니다.

calc %frameR%*2>tmpfile                  프레임레이트의 2배를 임시파일에 저장합니다.(thumbnail 필터의 값이 될 겁니다)

set /p thumb=<tmpfile                        임시파일값을 thumb 이라는 변수에 저장합니다.


계산값을 임시파일에 저장했다가 다시 불러오는 이런 짓을 하는 이유는 배치파일에서 실수를 다루지 못하기 때문입니다. 제가 잘못 안 건지 몰라도 실수를 처리할 방법이 없었습니다. 그래서 궁여지책으로 실수값을 외부계산기로 계산하고 저장한 후 불러오는 것입니다.


cls                                                                그냥 깨끗해 보이려고.......

echo 총 프레임수 %frameC%, 총 재생시간 %secTime%초 입니다.

set /p num=스샷은 몇 장?                                 원하는 스샷 장 수를 num 이란 변수에 저장합니다. 총프레임수보다 적은 값으로 지정.

set  qual=0                                                     품질을 qual 이란 변수에 저장합니다. 0으로 설정해 놓았습니다.


calc %dura%/(%num%*1000)>tmpfile   커맨드 라인 계산기로 총재생시간/(스샷장수*1000) 계산 --> 이미지추출 시간간격입니다.

                                                       1000이 들어가는 이유는 mediainfo로 읽어오는 시간값이 ms단위이기 때문입니다.

set /p inter=<tmpfile                           임시파일의 값을 불러와 inter 라는 변수에 저장합니다.


set setTime=0           스샷을 추출할 시작시간을 저장할 변수입니다. 초기값0입니다.(단위 초)

                              특정 부분에서 시작하고 싶으면 이 값을 변경하거나 첨부된 flv스샷2.bat를 쓰시면 됩니다.

set count=0              반복구간을 만들기 위한 변수입니다.


:LOOP

set /a count+=1        1씩 증가시키면서 스샷 장 수까지 올릴 겁니다


for %%e in (*.flv) do (

    if not exist %%~ne_thumbnail md %%~ne_thumbnail                파일이름_thumbnail이란 폴더가 없다면 새로 만듭니다.

    ffmpeg -vsync 2 -ss %setTime% -i "%%~ne.flv" -an -r %frameR% -vf thumbnail=%thumb% -q %qual% "%%~ne_thumbnail\%%~ne_0%count%.jpg"

                       ffmpeg 실제 추출 부분입니다. 옵션의 설명은 밑에 있습니다.

)

calc %setTime%+%inter%>tmpfile            스샷을 추출할 시간을 일정시간(총시간/스샷 장 수)만큼 증가 시키고 임시파일에 저장합니다.

set /p setTime=<tmpfile                           임시파일의 값을 불러와 저장합니다. 역시 실수이기 때문에 이런 과정을 거칩니다.

if %count% EQU %num% goto QUIT         카운트가 스샷 장 수에 도달했으면 루프구간을 빠져나갑니다.

goto LOOP


:QUIT

del tmpfile              임시파일을 지웁니다.

exit                       끝      



4. ffmpeg 옵션설명


ffmpeg -vsync 2 -ss %setTime% -i %%~nc.flv -an -r %frame% -vf thumbnail=%thumb% -q %qual% "%%~nc_0%count%.jpg"


-vsync 2 :  비디오 동기 방법

    이 옵션을 쓰지 않았을 경우 -vframes과 -r을 이용한 방법에서 처음 2장의 이미지가 시간차가 거의 없이 추출됩니다.

    vsync 2 로 설정하니 비교적 정상적으로 추출되는 것 같습니다.

-ss %setTime% : 이미지 추출을 시작할 시간을 설정합니다. 시간은 setTime 이란 변수에서 가져옵니다.

    mediainfo에서 읽어오는 값의 단위는 ms이므로 양쪽의 단위를 주의해야 합니다.

    그리고 가장 중요한 점은 -ss 옵션이 -i 옵션보다 먼저 나와야 합니다.

-i %%~nc.flv : 이미지를 추출할 원본 동영상 파일을 지정합니다. 배치파일문법을 사용해서 처음보는 분은 이상하게 보일 겁니다.

-an : 오디오를 끄는 기능입니다. 이미지만 추출하면 되기 때문에 속도가 조금이라도 올라갈가 싶어서 써봤습니다. 없어도 됩니다.

-r %frame% : 동영상의 프레임 레이트를 변경합니다. 원본 프레임레이트 정보가 있는 frame 이란 변수에서 값을 가져옵니다.

    시간만 맞추면 되기 때문에 동영상 원래의 프레임레이트를 넣었습니다.

-vf thumbnail=%thumb% : video 필터중에 하나입니다. 연속된 프레임 중에서 가장 대표적인 프레임을 선택해 줍니다.

    썸네일 뽑기에는 괜찮은 기능입니다. 동영상 프레임레이트 2배(대략 2초)로 설정해 놓았습니다.

-q %qual% : 출력 품질을 정합니다. 0 - 31 까지의 값을 쓸 수 있고(이점은 정확한지 모르겠습니다)

    숫자가 작을 수록 품질이 좋습니다. 가장 좋은 품질이라도 jpg라 1장당 용량이 수십kbyte 에서 수백 kbyte 밖에 안됩니다.

"%%~nc_0%count%.jpg" : 출력파일 이름. 여기서는 jpg이미지로 되어 있습니다.

    이름이 이상한 것은 배치파일 문법을 찾아보시면 이해하실 수 있습니다.


보다 자세한 설명은 http://blog.daum.net/nbdjj1998/83



5. 다른 방법


다른 방법들을 동영상 전체구간에서 고르게 이미지 추출하는 경우에 대한 적용입니다. 중간에 불편하다고 말하는 것은 이 방법들이 나쁘다는 의미가 아니라 전체구간에서 고르게 추출하는 목적에 맞지 않는다는 걸 의미하는 것입니다. 매우짧은 시간 동안 연속된 프레임을 추출하는 데에 적합한 방법입니다.


(1) -vframes, -r 2개의 옵션을 사용한 방법


보통 다음과 같은 형식입니다.

ffmpeg -vsync 2 -i <입력파일> -an -vframes <추출수> -r <프레임레이트> -ss <시작시간> -q <품질> <출력파일.jpg>


결론부터 말하면 -vframes 는 원하는 스샷 장수

-r원하는 스샷장수/동영상 재생시간 으로 하되, 0.05보다 크게 해야 합니다.


스샷장수, 프레임레이트, 동영상 재생시간의 관계는 다음과 같습니다.

(프레임레이트 R) : 1 = ( 프레임 수 N) : ( 프레임 수의 시간 T )


예를 들어 다음과 같은 flv 동영상이 있다고 가정하겠습니다.

프레임 레이트 30, 재생시간 38초


여기서 10장의 스샷을 뽑고 싶다고 하겠습니다.

그냥 -vframe 10 이렇게 쓰면 시작부터 10개의 프레임을 뽑습니다. (-r 이 동영상 프레임레이트와 같은 30이라고 가정하면)

30개가 모여야 1초가 되는데 10개니까

30 : 1 = 10 : T

T = 1/3 = 0.33...       대략 0.3 초 동안의 동영상에서 10장의 스샷을 뽑은 게 됩니다.


이 때는 T 를 동영상 전체 재생시간으로 하면 R 값을 구할 수 있습니다.

동영상 재생시간이 38초 니까

R : 1 = 10 : 38

R = 10/38   이 되고, 배치파일에서 다음과 같이 -vframe 값과 -r 값을 설정하면 됩니다.

ffmpeg -vsync 2 -i <입력파일> -vframes 10 -r 10/38 <출력파일.jpg>

이렇게 쓰면 동영상 전체구간에서 골고루 10장의 스샷을 뽑게 됩니다.


그런데 한가지 문제가 있습니다. R 값은 최저값이 0.05로 정해져 있습니다.(실험해 볼 때 이 보다 작은 값은 에러가 나더군요)

즉, 10 장의 스샷을 원한다면

0.05 : 1 = 10 : T

T = 200  이 되므로, 200초가 넘는 길이의 동영상에서는 골고루 10장의 스샷을 뽑을 수 없습니다.

그래서 스샷장수를 늘려야 합니다.


예를 들어 동영상 재생시간이 735초라고 하면,

0.05 : 1 = N : 735

N = 735*0.05 = 36.75    즉, 37이상으로 하면 됩니다. 그러나 1시간짜리 동영상이라면 몇 백장을 뽑아야 된다는 이야기니 좀 피곤하죠.

ffmpeg -vsync 2 -i <입력파일> -vframes 37 -r -0.05 <출력파일.jpg>

이런식으로 쓰면 동영상 전체에 걸쳐 골고루 썸네일용 이미지를 뽑을 수 있지만 비효율적이고,


-vframes 와 -r 옵션을 사용해서 스샷을 뽑을 때는 -ss 와 -t를 같이 사용해서 전체구간이 아니라 일부구간을 지정하는 것이 좋습니다.



(2) 프레임 선택을 이용한 방법도 있습니다.


다음과 같은 형태로 씁니다.

ffmpeg -vsync 2 -i <입력파일> -an -vf "select='not(mod(n,<프레임수>))'"  <출력파일.jpg>


프레임수에 특정 자연수값을 써넣으면 그 값만큼 건너 뜁니다.

예를 들어 select='not(mod(n,200))' 이라고 쓰면 200프레임을 건너 뛰기 때문에

결과적으로 동영상 처음부터 200프레임 간격으로 이미지를 추출하게 됩니다.

(1)방법에 비해 -r 옵션 제한이 없으니 좀 더 나은 방법입니다.

그래도 골고루 뽑기 위해서는 동영상 정보를 확인해서 총프레임수/뽑을 스샷수 계산을 해서 지정해야 하니 불편합니다.


(1), (2) 방법 모두 동영상을 처음부터 검색하면서 이미지를 추출하기 때문에 시간이 약간 걸리는 편입니다.

그래서 넓은 재생구간에서의 추출에는 적합하지 않습니다. 좁은 시간대 구간에서의 추출에 적합한 방법들입니다.

넓은 시간대에서 추출하려면 시간을 기준으로 탐색하는 것이 가장 좋습니다.




(3) 썸네일 필터를 사용해도 됩니다.


ffmpeg -vsync 2 -ss <시작시간> -i <입력파일> -an -r <프레임레이트> -vf thumbnail -q <품질> <출력파일.jpg>


간단히 -vf thumbnail 이란 문구를 추가하면 됩니다. 연속된 프레임 중 대표적인 프레임을 선택추출하게 됩니다.

-vf thumbnail=<프레임수> 의 형태로 쓰게 됩니다. 기본값은 100으로 100프레임 마다 대표이미지 하나씩을 추출하게 됩니다.

ffmpeg 홈페이지의 문서에 따르면 너무 큰 값은 많은 메모리를 요구하기 때문에 권장하지 않는다고 합니다.

써보니 위의 (1),(2) 방법에 비해도 빠른 편이고 선택되는 이미지도 가장 나은편입니다.

가령 -vf thumbnail=50 이라고 쓰면 50프레임 마다 대표이미지 한 장을 추출하는 것이 됩니다.

기본값이 100이므로 25프레임 영상에서는 4초당 1장, 60프레임 영상에서는 1.6초당 1장씩 추출됩니다.




 댓글 (0)


이미지
페이지: 1 / 1   


   타블렛/와콤 뱀부 3세대 타블렛/태블릿/무선타블렛/1830
     [RE] 타블렛/와콤 뱀부 3세대 타블렛/태블릿/무3
       [RE] 타블렛/와콤 뱀부 3세대 타블렛/태블릿/3
         [RE] 타블렛/와콤 뱀부 3세대 타블렛/태블릿6
           [RE] 타블렛/와콤 뱀부 3세대 타블렛/태블2
ffmpeg로 동영상에서 jpg 이미지 추출방법4720
   인터넷에 사진을 올리면 사진이 어둡게(푸른산)1970
   포토샵 - 도장툴1845
   포토샵 - 색상 보정1726
   포토샵- 색상대체2235
   움직이는 gif 민들기1693
   사진 해상도 낮추는법4904
   홈페이지에 메뉴 만들기...(홈마스타)1863
   배너만들기(홈마스타)1934
   배너 만들기(홈마스타)1756
   포토샵으로 배너 만들기(홈마스타)2012
   이미지 싸이즈 줄이는 방법(홈마스타)1605
≪ [1]   ≫

복수단어 검색은 공백(space)로 구분해 주세요.



 
최근 글
[손님]
117
97
250
467
1019
403
464
258
383
3841
931
1003
1248
990
4296
 
인기 글
[손님]
3218
3207
4128
3177
3821
3230
3188
3126
3573
3068
3081
7642
3192
4148
5672