Ffmpeg invalid data when trying to merge videos - python

I have a below function for merging videos in Python without re-encoding using FFmpeg:
def merge():
"""
This function merges a group of videos into one long video.
It is used for merging parts that are cut from original video into a new one.
The videos are merged using ffmpeg and for the ffmpeg
to use the concat method on them, the video names must be put inside
the vidlist.txt file.
New video is saved to the file named output.mp4.
"""
command = "ffmpeg -hide_banner -loglevel error -f concat -safe 0 -i vidlist.txt -c copy output.mp4"
# merge multiple parts of the video
subprocess.call(command, shell=True)
I store paths to videos to be merged inside a vidlist.txt file which looks like:
file 'out11.mp4'
file 'out21.mp4'
But, I am getting the following error:
vidlist.txt: Invalid data found when processing input
Here is the report file:
ffmpeg started on 2020-07-30 at 20:23:53
Report written to "ffmpeg-20200730-202353.log"
Log level: 48
Command line:
ffmpeg -hide_banner -f concat -safe 0 -i "C:\\Users\\miliv\\videocutter\\utils\\vidlist.txt" -c copy output.mp4 -report
Splitting the commandline.
Reading option '-hide_banner' ... matched as option 'hide_banner' (do not show program banner) with argument '1'.
Reading option '-f' ... matched as option 'f' (force format) with argument 'concat'.
Reading option '-safe' ... matched as AVOption 'safe' with argument '0'.
Reading option '-i' ... matched as input url with argument 'C:\Users\miliv\videocutter\utils\vidlist.txt'.
Reading option '-c' ... matched as option 'c' (codec name) with argument 'copy'.
Reading option 'output.mp4' ... matched as output url.
Reading option '-report' ... matched as option 'report' (generate a report) with argument '1'.
Finished splitting the commandline.
Parsing a group of options: global .
Applying option hide_banner (do not show program banner) with argument 1.
Applying option report (generate a report) with argument 1.
Successfully parsed a group of options.
Parsing a group of options: input url C:\Users\miliv\videocutter\utils\vidlist.txt.
Applying option f (force format) with argument concat.
Successfully parsed a group of options.
Opening an input file: C:\Users\miliv\videocutter\utils\vidlist.txt.
[concat # 000001aaafb8e400] Opening 'C:\Users\miliv\videocutter\utils\vidlist.txt' for reading
[file # 000001aaafb8f500] Setting default whitelist 'file,crypto,data'
[AVIOContext # 000001aaafb97700] Statistics: 0 bytes read, 0 seeks
C:\Users\miliv\videocutter\utils\vidlist.txt: Invalid data found when processing input

The issue was that I was trying to merge video before closing the vidlist.txt file which then didn't allow ffmpeg to open it

Related

Can moviepy be used without reencoding video

I wish to combine a remastered audio track to a video without re-encoding the source video.
I could achieve this with ffmpeg by running this command:
ffmpeg -i original_video.mp4 -i remastered_audio.wav -map 0:v -map 1:a -c:v copy -shortest remastered_video.mp4
The resulting remastered_video.mp4 file will be slightly larger than original_video.mp4 because the video track will be untouched and include the new encoded audio track. I wish to use moviepy to achieve the same, but I can't figure out how to do it without re-encoding the source video.
from moviepy.editor import AudioFileClip, VideoFileClip
original_video = VideoFileClip(<path_to_original_video_file.mp4>)
remastered_audio = AudioFileClip(<path_to_remastered_audio_track.wav>)
remastered_video = original_video.set_audio(remastered_audio)
remastered_video.write_videofile(<path_of_output_remastered_video.mp4>)
Here the output video file will be smaller than the source because the video track was re-encoded.
I then tried to pass my ffmpeg arguments like so:
args=['-map', '0:v', '-map', '1:a', '-c:v', 'copy']
remastered_video.write_videofile(<path_of_output_remastered_video.mp4>,
ffmpeg_params=args,
logger=None)
but that generated the following error:
#[mp4 # 00000190c731d280] Could not find tag for codec rawvideo in stream #0, codec not currently supported in container
#Could not write header for output file #0 (incorrect codec parameters ?): Invalid argument
QUESTION
I know how to use subprocess to directly run ffmpeg, but I would like to avoid this and use moviepy. Is it possible to tell moviepy to copy the source video instead of re-encoding it, similar to the ffmpeg example command I posted above?

Issues in python based ffmpeg operation

I am trying to write a script that would automatically take duration values and chop an audio file into smaller splits. To do this I have saved all my start times and durations in a list. And this is the code I am trying to run.
for k in range(0,len(start_time)):
s=start_time[k]
e=Duration[k]
filename = "output%d.mp3" % (k)
!ffmpeg -i Audio.mp3 -ss s -t e -acodec copy filename
k=k+1
On running this I get the following error
Invalid duration specification for ss: s
I suspect that this error arises because of the fact that since I am using lists to call elements, the time stamp comes with quotes on both sides. Secondly, I am not sure how to specify the filename, such that each created split has the name of this format Output_1.mp3 and so on. The integer will be an identifier of the split. What could be possible fixes for this piece of code? Please note that I am running this on Google Colab.
Google Colab is running Jupyter notebook powered by IPython in its cloud, IPython uses special syntax for shell invocation (commands starting from ! exclamation mark), i.e. they are executed in (temporary) shell session. In case of Google Colab it's bash:
res = !echo $SHELL
print(res)
> ['/bin/bash']
As I checked, ffmpeg is indeed available on Google Colab:
res = !which ffmpeg
print(res)
> ['/usr/bin/ffmpeg']
, so you have legitimate error message printed by ffmpeg: "Invalid duration specification ... " (I mean not by shell or python) and it just means that variable you're passing is not substituted with its value the way you do. And it's so because this above mentioned special syntax is not followed for passing variable to the shell, check this; variables should be curly-braced to be passed:
!ffmpeg -i Audio.mp3 -ss {s} -t {e} -acodec copy {filename}

Can I pass a list of image into the input method of ffmpeg-python

My task involves using ffmpeg to create video from image sequence.
the code belows solves the problem.
import ffmpeg
video = ffmpeg.input('/path/to/images/*.jpg', pattern_type='glob',framerate=20).output(video.mp4).run()
However since the image data we are getting follows the pattern
1.jpg,
2.jpg,
3.jpg
.
.
20.jpg
.
.
100.jpg
the video get created with the glob pattern 1.jpg, 100.jpg, 11.jpg, 12.jpg, ... 2.jpg, 20.jpg, 21.jpg ... which is very unpleasant to watch.
Is there anyway I can pass a list or anything else aside a path/glob pattern where the images are sorted in order.
Also as a bonus I will be happy if I can choose which files to add as an the input method input()
You may use Concat demuxer:
Create a file mylist.txt with all the image files in the following format:
file '/path/to/images/1.jpg'
file '/path/to/images/2.jpg'
file '/path/to/images/3.jpg'
file '/path/to/images/20.jpg'
file '/path/to/images/100.jpg'
You may create mylist.txt manually, or create the text file using Python code.
Use the following command (you may select different codec):
ffmpeg.input('mylist.txt', r='20', f='concat', safe='0').output('video.mp4', vcodec='libx264').run()
Second option:
Writing JPEG data into stdin PIPE of FFmpeg sub-process.
Create a list of JPEG file names (Python list).
Execute FFmpeg sub-process, with stdin PIPE as input, and jpeg_pipe input format.
Iterate the list, read the content of each file and write it to stdin PIPE.
Close stdin PIPE.
Here is a code sample:
import ffmpeg
# List of JPEG files
jpeg_files = ['/tmp/0001.jpg', '/tmp/0002.jpg', '/tmp/0003.jpg', '/tmp/0004.jpg', '/tmp/0005.jpg']
# Execute FFmpeg sub-process, with stdin pipe as input, and jpeg_pipe input format
process = ffmpeg.input('pipe:', r='20', f='jpeg_pipe').output('/tmp/video.mp4', vcodec='libx264').overwrite_output().run_async(pipe_stdin=True)
# Iterate jpeg_files, read the content of each file and write it to stdin
for in_file in jpeg_files:
with open(in_file, 'rb') as f:
# Read the JPEG file content to jpeg_data (bytes array)
jpeg_data = f.read()
# Write JPEG data to stdin pipe of FFmpeg process
process.stdin.write(jpeg_data)
# Close stdin pipe - FFmpeg fininsh encoding the output file.
process.stdin.close()
process.wait()

Why is the -f flag not working in ffmpeg in python

ffmpeg.output(audioo, videoo, name).global_args("-f mp4").run()
I have this code which takes in the audio and video, and gives the output file a name.
Then I have .global_args, which takes in the arguments, but, when I try to run the script
it says
Unrecognized option 'f mp4'.
Error splitting the argument list: Option not found
But, if I use a flag like, -y which looks like this
ffmpeg.output(audioo, videoo, names).global_args("-y").run()
it works but then in the name string, It needs to be like 'output.mp4'
but I want to use the -f flag so It could be 'output' only, and the format is decided by the flag.
You may think it's useless but if it's needed I could explain my reasons further.

Joining multiple CSV Files

I have a folder with multiple csv files. Every file consists of a date and a value column. I would like to merge all files into one where the first column consists of the value date (which is the same for each file) and the other columns are populated by the values of each single vile i.e. (date, value_file1, value_file2...)
Any suggestions on how this could be achieved via a simple python script or maybe evan through a unix command?
Thank you for your help!
I'd recommend using a tool like csvkit's csvjoin
pip install csvkit
$ csvjoin --help
usage: csvjoin [-h] [-d DELIMITER] [-t] [-q QUOTECHAR] [-u {0,1,2,3}] [-b]
[-p ESCAPECHAR] [-z MAXFIELDSIZE] [-e ENCODING] [-S] [-v] [-l]
[--zero] [-c COLUMNS] [--outer] [--left] [--right]
[FILE [FILE ...]]
Execute a SQL-like join to merge CSV files on a specified column or columns.
positional arguments:
FILE The CSV files to operate on. If only one is specified,
it will be copied to STDOUT.
optional arguments:
-h, --help show this help message and exit
-d DELIMITER, --delimiter DELIMITER
Delimiting character of the input CSV file.
-t, --tabs Specifies that the input CSV file is delimited with
tabs. Overrides "-d".
-q QUOTECHAR, --quotechar QUOTECHAR
Character used to quote strings in the input CSV file.
-u {0,1,2,3}, --quoting {0,1,2,3}
Quoting style used in the input CSV file. 0 = Quote
Minimal, 1 = Quote All, 2 = Quote Non-numeric, 3 =
Quote None.
-b, --doublequote Whether or not double quotes are doubled in the input
CSV file.
-p ESCAPECHAR, --escapechar ESCAPECHAR
Character used to escape the delimiter if --quoting 3
("Quote None") is specified and to escape the
QUOTECHAR if --doublequote is not specified.
-z MAXFIELDSIZE, --maxfieldsize MAXFIELDSIZE
Maximum length of a single field in the input CSV
file.
-e ENCODING, --encoding ENCODING
Specify the encoding the input CSV file.
-S, --skipinitialspace
Ignore whitespace immediately following the delimiter.
-v, --verbose Print detailed tracebacks when errors occur.
-l, --linenumbers Insert a column of line numbers at the front of the
output. Useful when piping to grep or as a simple
primary key.
--zero When interpreting or displaying column numbers, use
zero-based numbering instead of the default 1-based
numbering.
-c COLUMNS, --columns COLUMNS
The column name(s) on which to join. Should be either
one name (or index) or a comma-separated list with one
name (or index) for each file, in the same order that
the files were specified. May also be left
unspecified, in which case the two files will be
joined sequentially without performing any matching.
--outer Perform a full outer join, rather than the default
inner join.
--left Perform a left outer join, rather than the default
inner join. If more than two files are provided this
will be executed as a sequence of left outer joins,
starting at the left.
--right Perform a right outer join, rather than the default
inner join. If more than two files are provided this
will be executed as a sequence of right outer joins,
starting at the right.
Note that the join operation requires reading all files into memory. Don't try
this on very large files.

Categories

Resources