'ffmpeg - how to handle video and audio URL's streams separately?
I am trying to create a zsh
function that uses youtube-dl
and ffmpeg
to download a portion of a YouTube video. I did achieve this goal with the following function:
# $1 - youtube URL
# $2 - start position in hh:mm:ss.msms format (ms=miliseconds)
# $3 - final position in hh:mm:ss.msms format (ms=miliseconds)
# $4 - output file name (optional)
function youtubedl_snippet()(
local url_stream=$(youtube-dl -f best --get-url $1)
local output_name=$(youtube-dl --get-title $1)
ffmpeg -ss $2 -to $3 -i $url_stream -c:v copy -c:a copy ${4:-"$output_name.mp4"}
)
The command youtube-dl -f best --get-url $1
return a single URL with the best possible quality. In order to understand better how ffmpeg
works, I tried to create another function with the same goal but with a different approach:
# $1 - youtube URL
# $2 - start position in hh:mm:ss.msms format (ms=miliseconds)
# $3 - final position in hh:mm:ss.msms format (ms=miliseconds)
# $4 - output file name (optional)
# $5 - output video codec type (optional, for instance: libx264)
# $6 - output audio codec type (optional, for instance: aac)
function youtubedl_snippet2()(
local url_streams=$(youtube-dl --get-url $1)
local output_name=$(youtube-dl --get-title $1)
local url_array=(${(f)url_streams}) # expand urls by lines url_array[1] -> video stream url_array[2] -> audio stream
ffmpeg -ss $2 -to $3 -i ${url_array[1]} -ss $2 -to $3 -i ${url_array[2]} -map 0:v -map 1:a -c:v ${5:-copy} -c:a ${6:-copy} ${4:-"$output_name.mp4"}
)
What I suppose that is going on here:
url_streams
is a line-separated URL.url_array[1]
is the video URL andurl_array[2]
is the audio URL.- I am setting both audio and video to the same intervals.
- I mapped the first stream to video, and the second to audio
- If
$5
and$6
does not give different codecs,ffmpeg
just copy from the original source.
Well, it seems that everything is ok. But when I try
start=$SECONDS; youtubedl_snippet2 'https://www.youtube.com/watch?v=g-_hVXzkn0o' 00:00:05.00 00:00:15.00; echo "it takes $(( SECONDS - start )) seconds"
It will take 368 seconds. Moreover, I cannot open it in my android (only audio works)
On the other hand,
start=$SECONDS; youtubedl_snippet 'https://www.youtube.com/watch?v=g-_hVXzkn0o' 00:00:05.00 00:00:15.00; echo "it takes $(( SECONDS - start )) seconds"
takes only 40 seconds, and the video can be played on Android.
Here is the youtubedl_snippet
log file. And here is the youtubedl_snippet2
log file.
Solution 1:[1]
The first video is 720P while the second is 4K. That's why it takes much longer to copy the latter.
As for why "Can't play video. video codec not supported." If you look at the log, the 4K video is encoded in VP9. While MP4 can carry VP9 stream, it is not standard, and Android player either does not support VP9 in MP4 or is not shipped with VP9 decoder. Try changing the second output filename to $output_name.mkv
and see if Android player can handle the matroska-vp9 combo. Otherwise, you need to explore different YouTube video stream options and pick the one with the highest resolution encoded in h264.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | kesh |