Reputation: 9724
Given the following directory structure...
my-project
+ frames
+ frame-1.jpg
+ frame-2.jpg
...
+ frame-200.jpg
+ locales
+ default
| + music.mp3
+ en
+ music.mp3
For each locale in directory locales
(default
and en
) I need to:
ffprobe
to determine the DURATION
in seconds of the audio file (*.mp3
);jpg
frames that form the final video, which is used for all the locales;FRAMERATE
(FRAMERATE = 1 / (DURATION / FRAMES)
);ffmpeg
to create an mp4 video out of the jpg
frames and the audio file, using the calculated FRAMERATE
.Here below is an extract of my Makefile
:
.DEFAULT_GOAL := build
FRAMES_DIR := ${CURDIR}/frames
LOCALES_DIR := ${CURDIR}/locales
OUTDIR:= ${CURDIR}/build
.PHONY: build
build:
@for dir in $(shell find $(LOCALES_DIR) -type d -depth 1 -exec base name {} \;); do
$(eval DURATION := $(shell ffprobe -v error -show_entries format=duration -of \
default=noprint_wrappers=1:nokey=1 $(LOCALES_DIR)/$$dir/*.mp3)); \
$(eval FRAMES := $(shell ls $(FRAMES_DIR) | wc -l))
$(eval FRAMERATE := $(shell awk "BEGIN {print 1 / ($(DURATION) / $(FRAMES))}"))
ffmpeg -y -framerate $(FRAMERATE) -start_number 1 -i $(FRAMES_DIR)/frame_%d.jpeg -i $(LOCALES_DIR)/$$dir/*.mp3 \
-c:v libx264 -pix_fmt yuv420p -c:a aac -strict experimental \
-shortest $(OUTDIR)/$video-$$dir.mp4; \
done;
And here's the expected result:
my-project
+ build
+ video-default.mp4
+ video-en.mp4
The problem is that the ffprobe
command fails as the input path is wrong, i.e. $$dir
does not contain the expected subdirectory name (default
or en
). Long story short, it seems $$dir
is not visible inside $(shell ...)
.
Am I missing something? Thanks.
Upvotes: 1
Views: 138
Reputation: 4750
Try using a multiline shell script, as below:
build:
find "${LOCALES_DIR}" -type d -depth 1 -exec base name {} \; | while read -r dir; \
do \
DURATION="$$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "${LOCALES_DIR}/$$dir"/*.mp3)"; \
FRAMES="$$(ls -1 "$$FRAMES_DIR" | wc -l)"; \
FRAMERATE="$$(awk "BEGIN {print 1 / ($$DURATION / $$FRAMES)}")"; \
ffmpeg -y -framerate "$$FRAMERATE" -start_number 1 -i "$$FRAMES_DIR"/frame_%d.jpeg -i "${LOCALES_DIR}/$$dir"/*.mp3 \
-c:v libx264 -pix_fmt yuv420p -c:a aac -strict experimental \
-shortest "${OUTDIR}"/$$video-"$$dir".mp4 < /dev/null; \
done;
I made some changes:
while read
loop to avoid problems with paths with spaces-1
to ls
so that each item is printed on its own line, which should ensure wc -l
gives an accurate count/dev/null
as stdin to ffmpeg
so that ffmpeg
can't interfere with the while read
loopUpvotes: 4