0. 개요


cmd에서는 명령을 입력하면 명령어를 한 줄씩 실행한다.
즉, 한 줄 실행이 완료될 때 까지 기다리고, 완료되면 그 다음 줄을 실행한다.
이전 회사에서, 한번에 여러개의 디바이스를 다룰 일이 많았다.

아래 예시를 보면, 두개의 디바이스가 연결된 상태에서 screencap 명령어를 통해 스크린샷을 찍어보았다.

위와 같이, more than one device/emulator 에러 메세지가 나오면서 실행이 되지 않는다!


1. -s 옵션

컴퓨터 입장에서 보면, "어떤 디바이스로 해달라는거야?" 라고 되물을 것이다.

우리는 그래서, 직접 이름을 불러주고 명령을 해야한다.

adb devices 명령어를 입력하면 연결되어있는 디바이스의 이름(시리얼넘버) 확인이 가능하다.

아래와 같이 -s 옵션을 붙이면 디바이스를 지정할 수 있다!


2. 직렬 실행

그렇다면, 한번에 두개를 실행하고 싶다면 어떻게 해야 가능할까?

이렇게 두 줄 쓰는 방법도 있을것이다.

하지만 다음과 같이 생각할 내용이 있다.

만약 스크립트가 길어진다면?

set device_1=R3CRA0JW89R
set device_2=R3CX208V22K

adb -s %device_1% shell screencap -p /sdcard/screenshot.png
adb -s %device_2% shell screencap -p /sdcard/screenshot.png

adb -s %device_1% shell screencap -p /sdcard/screenshot1.png
adb -s %device_2% shell screencap -p /sdcard/screenshot1.png

adb -s %device_1% shell screencap -p /sdcard/screenshot2.png
adb -s %device_2% shell screencap -p /sdcard/screenshot2.png

이렇게 길게 작성해야한다..

그리고 또 아래와 같은 문제점이 있다.

  1. 만약 시리얼 넘버가 계속 바뀐다면?
    이런 상황이 있을 수도 있다. 같은 디바이스에서는 같은 시리얼 넘버가 출력되지만, 만약 디바이스를 계속 바꾸면서 하는 경우도 있다.
  2. 만약 스크린샷 찍는것 뿐만 아니라 스크립트가 더 있고, 하나 완료하는데 몇분씩 걸린다면?
    처음 말했듯, cmd에서는 코드를 한줄씩 읽고 실행한다.
    만약 디바이스가 10대라고 가정하면, 1대의 디바이스가 스크립트 실행중일때 나머지 9대의 디바이스는 아무것도 안하는 상태로 있는다.

이미지로 비유하자면, 아래와 같다.

그렇다면 이게 한계일까?

 

그렇지 않다!

다소 억지스럽지만, cmd에서는 병렬 실행을 구현할 수 있다.


3. 병렬 실행

우리가 원하는건 아래 이미지와 같은 병렬 실행이다.

그러기 위해서, 디바이스 만큼 cmd 스크립트를 실행하는 방법으로 구현해냈다.

우선, 아래와 같은 폴더 구조를 만들었다.

order.bat에서는, 다음과 같은 스크립트가 들어가있다.

@echo off
setlocal enabledelayedexpansion

for /f "skip=1" %%i in ('adb devices | findstr "devices"') do (
    start /min capture.bat %%i
)

복잡한 명령어긴 하지만, 단순하게 설명하자면

  1. 'adb devices'를 실행한다.
  2. 거기서, | findstr devices (파이프)를 이용해 devices인 경우를 필터(디바이스가 오프라인, 인증되지 않은 경우 제외)
  3. skip=1 을 통해 adb devices의 List of devices attached 구문을 무시하고, 시리얼 넘버를 가져온다.
  4. start /min 옵션을 통해, 최소화된 창으로 capture.bat을 실행한다.
  5. 다만, capture.bat에 %%i 를 통해 시리얼넘버를 같이 실어서 보내준다.

capture.bat에서는, %1을 통해 해당 시리얼 넘버를 사용할 수 있다.

echo %1 시리얼 넘버를 넘겨받았습니다.
pause>nul

capture.bat을 위와같이 설정하고, 실행한다면

이렇게 시리얼넘버를 넘겨 받을 것을 확인할 수 있다.

그렇다면,

이제 이런식으로 작성하면 다소 억지스럽지만 병렬 실행을 구현할 수 있다.


4. 결론

억지스럽다 표현한 이유는, 저렇게 실행하면 실행한 수 만큼 cmd가 켜지기 때문이다..

그래도 조금은 투박하지만 분명한 성과는 있었다.

3분정도 걸리는 스크립트를 6개의 디바이스에 직렬로 실행했을 때에는 18분 가량 걸리곤 했었는데, 병렬 구현을 한 후에는 약 5분정도 걸리게 되었다. (병렬로 실행하면서 렉이 좀 걸리니까 느려지면서 추가됨)

파이썬에는 아예 병렬 실행을 하는 쓰레딩 라이브러리가 있는 것으로 알고 있다.

이후 실무에서 만약 병렬 실행 수요를 마주친다면 한번쯤 활용해보면 될 것 같다.

0. 개요

이전 포스트 (https://janguri.tistory.com/8) 에서 ffmpeg를 이용해 영상을 효율적으로 다루게 되었다.

이번 글에서는, 이전에 만든 배치파일들을 효율적으로 통합하여 사용하는 방법을 소개한다.


1. Batch Script 통합

먼저 개인적인 경험을 소개하자면, 첫 회사에서 맨땅에 배치 스크립트를 만들면서 아래 이미지처럼 배치 스크립트가 많아져 불편한 경험이 있었다.

그래서, 최종적으로 하나의 통합 툴을 만들어 사용을 조금 더 편리하게 개선하게 되었다.

위 이미지와 같이 여러 배치 스크립트를 하나에 모아두고, 숫자를 입력 해 해당하는 행동을 하는 통합 툴을 만들어냈다.


2. 통합 방식

숫자를 입력 받으면, 여러가지 방법이 있으나 경험 상 두가지 방법을 선택해 사용했다.

  1. batch 파일을 불러(call) 실행하기
  2. 한 배치 스크립트에 모든 명령어 다 집어넣고 그 명령어 찾아가(goto) 실행하기

1번 방식의 경우, 기존에 만들었던 배치파일을 한 폴더에 다 넣고 통합 배치 스크립트에서 필요할때 불러 쓰는 방식이다.

장점으로는, 수정이 필요하면 해당 배치 파일을 꺼내 수정하면 되니 편리하다는 점.

단점으로는, 폴더 하나가 더 있어서 거슬릴 수도 있다 정도?

2번 방식의 경우, 통합 배치 스크립트에 모든 스크립트를 때려박는 방식이다.

장점으로는, 배치스크립트 단 하나만 있으면 되니 매우 깔끔하다!

단점으로는, 수정이 필요할 때 하나하나 찾아가야하니 수정이 불편하다는 점.

아래 두 코드 예시를 보면 이해가 쉬울것이다.

 

REM 1번 방식 / call로 불러들이기

@echo off
:loop
cls
chcp 65001 >nul
echo [1] capture
echo [2] record
echo [3] compress
echo [4] cut
echo [5] gif
echo [6] png
set /p num="Select number : "

if %num%==1 call batch\capture.bat
if %num%==2 call batch\record.bat
if %num%==3 call batch\compress.bat
if %num%==4 call batch\cut.bat
if %num%==5 call batch\gif.bat
if %num%==6 call batch\png.bat
goto loop

1번 방식의 스크립트다.

숫자를 입력하면, call 명령어를 통해 batch 폴더 내의 배치스크립트를 실행시키고, loop를 통해 다시 처음 위치로 이동하는 형식이다.

REM 2번 방식 //goto 명령어로 찾아가기

@echo off
:loop
cls
chcp 65001 >nul
echo [1] capture
echo [2] record
echo [3] compress
echo [4] cut
echo [5] gif
echo [6] png
set /p num="Select number : "

if %num%==1 goto capture
if %num%==2 goto record
if %num%==3 goto compress
if %num%==4 goto cut
if %num%==5 goto gif
if %num%==6 goto png
goto loop

:capture
echo this is capture script
goto loop
:record
echo this is record script
goto loop
:compress
echo this is compress script
goto loop
:cut
echo this is cut script
goto loop
:gif
echo this is gif script
goto loop
:png
echo this is png script
goto loop

2번 방식의 스크립트다.

숫자를 입력하면, goto 명령어를 통해 원하는 위치로 이동해 스크립트를 실행하고, 다시 loop 위치로 이동하는 형식이다.

 

사실 첫 선택이 중요하진 않다. 규모가 커지기 전에 알맞게 리팩토링 하면 된다. ^ㅇ^

여기서는 1번 방식 (call) 을 사용하여 불러 쓰는, 파이썬으로 치면 모듈 호출과 같은 느낌으로 만들어 보겠다.


3. 호출

우선, 아래 이미지와 같은 폴더 구조를 만들었다.

Tool.bat에서 batch\실행할스크립트.bat 을 넣어주면 끝!

이전에 만들어 둔 캡쳐 스크립트를 capture.bat에 넣어준다.

set /p file_name="Input file name : "
adb shell screencap -p /sdcard/screenshot.png
adb pull /sdcard/screenshot.png %file_name%.png

그런 후, 숫자 1을 입력해 capture.bat이 작동하는지에 대해 확인을 하면

  1. [1] capture 을 입력해서
  2. batch\capture.bat 파일이 열리고
  3. capture.bat 파일이 끝날 때 goto loop을 통해 :loop으로 이동된다.

파일은 capture.bat이 위치한 폴더에 생성되지 않고 Tool.bat에서 생성된다.

 

set /p file_name="Input file name : "
echo Recording...
echo press Ctrl + C and "N" to quit recording
adb shell screenrecord /sdcard/record.mp4
adb pull /sdcard/record.mp4 %file_name%.mp4

*화면 녹화

set /p file_name="Input file name : " 
ffmpeg -i %file_name% -vcodec libx264 -crf 28 -preset slow output_%file_name%
cls
set /p answer=Delete Original? [y/n] :
if %answer%==n goto quit
if %answer%==N goto quit
del %file_name%
ren output_%file_name% %file_name%
:quit

* 영상 압축

** Deleter Original? 을 통해 변경 전의 파일을 지우고 압축된 파일을 기존 파일명으로 변경할지의 분기점을 추가했다.

 

set /p file_name="Input file name : " 
echo enter Start time and finish time...
set /p start_time="Start time : "
set /p finish_time="Finish time : "
ffmpeg -i %file_name% -ss %start_time% -to %finish_time% output_%file_name%
set /p answer=Delete Original? [y/n]
if %answer%==n goto quit
if %answer%==N goto quit
del %file_name%
ren output_%file_name% %file_name%
:quit

* 영상 자르기

 

set /p file_name="Input file name : " 
ffmpeg -i %file_name% -vf "fps=8, palettegen=max_colors=32" -y palette.png
ffmpeg -i %file_name% -i palette.png -filter_complex "fps=8,paletteuse=dither=bayer" -b:v 1000k %file_name:~0,-4%.gif
del palette.png
:quit

* gif 만들기

**배치 파일에서 문자열 추출 규칙을 활용해, %file_name:~0,-4%로 작성하였다. (0번째부터 출력하는데 뒤에 .mp4 제거)
참고 : https://sysdocu.tistory.com/1516

 

set /p file_name="Input file name : " 
if not exist frames md frames
set /p frame_per_second=" How may Frames per second? : "
ffmpeg -i %file_name% -vf "fps=%frame_per_second%" frames/%%d.png
start frames

*png 만들기

**파일명을 입력 후, 초당 프레임을 설정할 수 있는 방식으로 구현해냈다.

*** frames 폴더가 없으면 만들고, 작업 후 frames 폴더를 자동으로 실행하게 구현했다.

 


4. 오류

명령어를 통해 생성된 파일을 삭제하거나이동할때 문제가 발생할 수도 있다.

그럴때를 대비해, adb 명령어를 재시작하는 코드를 추가했다.

if %num%==7 adb kill-server

7번을 입력했을 때 , adb kill-server을 추가해줬다.

뭐.. 다른 방법이 있을 수도 있지만 그냥 단순히 이렇게 재시작해주는 방법으로 해결했다.

 


5. 결론

말고도, 배치 스크립트를 활용하는 방법이 무궁무진하다!

예로, 아래와 같이 이쁜 색상코드를 넣을 수도 있다. (ANSI ESCAPE CODE 검색)

바로 다음으로, 배치스크립트로 병렬 실행을 (다소 억지스럽게) 구현한 방법을 소개하고자 한다.

+ Recent posts