Merge pull request #3 from b4oshany/master

Added some additional features
This commit is contained in:
c0decracker 2016-02-08 14:19:39 -08:00
commit 5ec300a2f8
5 changed files with 214 additions and 24 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
*.pyc
*.mp4

View file

@ -4,11 +4,94 @@ Simple command line Python script that splits video into multi chunks. Under the
Run `python ffmpeg-split.py -h` to see the options. Here are few samples of how it could be used:
## Spliting video into equal chunks
`python ffmpeg-split.py -f big_video_file.mp4 -s 10`
This splits `big_video_file.mp4` into 10 chunks. Each chunk will be suffixed with numeric index, for example `big_video_file-0.mp4`, `big_video_file-1.mp4`, etc.
## Splitting videos into unequal chunks
[FFMpeg]: https://www.ffmpeg.org/
In order to create unequal chunks of a video, you'll need to create ***manifest.json***.
***manifest.json***
```json
[
{
"start_time": 0,
"length": 34,
"rename_to": "video1"
},
{
"start_time": 35,
"length": 22,
"rename_to": "video2.mp4"
}
]
```
Afterwards run:
`python ffmpeg-split.py -f big_video_file.mp4 -m manifest.json`
This splits `big_video_file.mp4` into 2 video files, video1.mp4 and video2.mp4. The video1.mp4 is a 34 seconds
clip, starting from 0:00 to 0:34 of the `big_video_file.mp4`.
Alternatively, you can use a ***manifest.csv*** file to accomplish the task above.
***manifest.csv***:
```CSV
start_time,length,rename_to
0,34,video1
35,22,video2
```
#### Manifest Options
* start_time - number of seconds into the video or start time
* length - length of the video in seconds. The end time of the video is calculated by the start_time plus the length of the video.
* rename_to - name of the video clip to be saved
* end_time - end time of the video
## Additional Arguments
* -v or --vcodec ffmpeg video codec to be used.
* -a or --acodec ffmpeg audio codec to be used.
* -m or --manifest manifest file to control the splitting of videos.
* -f or --file video file to split.
* -s or --split-size seconds to evenly split the videos
#### Notes:
The -s and -m options should not be used together. If they are, -m option takes
precedent over the -s option
## Known Issues with ffmpeg
* There might be some videos that aren't showing properly after splitting the source video with ffmpeg. To resolve
this, use the -v option and pass in the associated video codec for the source video or video format. For example, mp4 videos
use h264 video codec. Therefore, running the command
`python ffmpeg-split.py -f example.mp4 -s -v h264`, may resolve this issue.
## Installing ffmpeg
See [FFmpeg installation guide](https://www.ffmpeg.org/download.html) for details.
[FFMpeg]: https://www.ffmpeg.org/

3
examples/manifest.csv Normal file
View file

@ -0,0 +1,3 @@
start_time,length,rename_to
0,34,video1
35,22,video2
1 start_time length rename_to
2 0 34 video1
3 35 22 video2

17
examples/manifest.json Normal file
View file

@ -0,0 +1,17 @@
[
{
"start_time": 0,
"length": 34,
"rename_to": "video1"
},
{
"start_time": 35,
"length": 22,
"rename_to": "video2.mp4"
},
{
"start_time": 50,
"end_time": "00:01:20",
"rename_to": "video3.mp4"
}
]

132
ffmpeg-split.py Executable file → Normal file
View file

@ -1,22 +1,94 @@
#!/usr/bin/env python
import csv
import subprocess
import re
import math
import json
import os
from optparse import OptionParser
length_regexp = 'Duration: (\d{2}):(\d{2}):(\d{2})\.\d+,'
re_length = re.compile(length_regexp)
def main():
def split_by_manifest(filename, manifest, vcodec="copy", acodec="copy",
**kwargs):
""" Split video into segments based on the given manifest file.
(filename, split_length) = parse_options()
if split_length <= 0:
Arguments:
filename (str) - Location of the video.
manifest (str) - Location of the manifest file.
vcodec (str) - Controls the video codec for the ffmpeg video
output.
acodec (str) - Controls the audio codec for the ffmpeg video
output.
"""
if not os.path.exists(manifest):
print "File does not exist: %s" % manifest
raise SystemExit
with open(manifest) as manifest_file:
manifest_type = manifest.split(".")[-1]
if manifest_type == "json":
config = json.load(manifest_file)
elif manifest_type == "csv":
config = csv.DictReader(manifest_file)
else:
print "Format not supported. File must be a csv or json file"
raise SystemExit
split_cmd = "ffmpeg -i '%s' -vcodec %s -acodec %s -y " % (filename,
vcodec,
acodec)
split_count = 1
split_error = []
try:
fileext = filename.split(".")[-1]
except IndexError as e:
raise IndexError("No . in filename. Error: " + str(e))
for video_config in config:
split_str = ""
try:
split_start = video_config["start_time"]
split_length = video_config.get("end_time", None)
if not split_length:
split_length = video_config["length"]
filebase = video_config["rename_to"]
if fileext in filebase:
filebase = ".".join(filebase.split(".")[:-1])
split_str += " -ss " + str(split_start) + " -t " + \
str(split_length) + \
" '"+ filebase + "." + fileext + \
"'"
print "########################################################"
print "About to run: "+split_cmd+split_str
print "########################################################"
output = subprocess.Popen(split_cmd+split_str,
shell = True, stdout =
subprocess.PIPE).stdout.read()
except KeyError as e:
print "############# Incorrect format ##############"
if manifest_type == "json":
print "The format of each json array should be:"
print "{start_time: <int>, length: <int>, rename_to: <string>}"
elif manifest_type == "csv":
print "start_time,length,rename_to should be the first line "
print "in the csv file."
print "#############################################"
print e
raise SystemExit
def split_by_seconds(filename, split_length, vcodec="copy", acodec="copy",
**kwargs):
if split_length and split_length <= 0:
print "Split length can't be 0"
raise SystemExit
output = subprocess.Popen("ffmpeg -i '"+filename+"' 2>&1 | grep 'Duration'",
output = subprocess.Popen("ffmpeg -i '"+filename+"' 2>&1 | grep 'Duration'",
shell = True,
stdout = subprocess.PIPE
).stdout.read()
@ -30,13 +102,13 @@ def main():
else:
print "Can't determine video length."
raise SystemExit
split_count = int(math.ceil(video_length/float(split_length)))
if(split_count == 1):
print "Video length is less then the target split length."
raise SystemExit
split_cmd = "ffmpeg -i '"+filename+"' -vcodec copy "
split_cmd = "ffmpeg -i '%s' -vcodec %s -acodec %s " % (filename, vcodec,
acodec)
try:
filebase = ".".join(filename.split(".")[:-1])
fileext = filename.split(".")[-1]
@ -48,7 +120,7 @@ def main():
split_start = 0
else:
split_start = split_length * n
split_str += " -ss "+str(split_start)+" -t "+str(split_length) + \
" '"+filebase + "-" + str(n) + "." + fileext + \
"'"
@ -57,36 +129,50 @@ def main():
subprocess.PIPE).stdout.read()
def parse_options():
parser = OptionParser()
def main():
parser = OptionParser()
parser.add_option("-f", "--file",
dest = "filename",
help = "file to split, for example sample.avi",
help = "File to split, for example sample.avi",
type = "string",
action = "store"
)
parser.add_option("-s", "--split-size",
dest = "split_size",
help = "split or chunk size in seconds, for example 10",
help = "Split or chunk size in seconds, for example 10",
type = "int",
action = "store"
)
parser.add_option("-m", "--manifest",
dest = "manifest",
help = "Split video based on a json manifest file. ",
type = "string",
action = "store"
)
parser.add_option("-v", "--vcodec",
dest = "vcodec",
help = "Video codec to use. ",
type = "string",
default = "copy",
action = "store"
)
parser.add_option("-a", "--acodec",
dest = "acodec",
help = "Audio codec to use. ",
type = "string",
default = "copy",
action = "store"
)
(options, args) = parser.parse_args()
if options.filename and options.split_size:
return (options.filename, options.split_size)
if options.filename and options.manifest:
split_by_manifest(**(options.__dict__))
elif options.filename and options.split_size:
split_by_seconds(**(options.__dict__))
else:
parser.print_help()
raise SystemExit
if __name__ == '__main__':
try:
main()
except Exception, e:
print "Exception occured running main():"
print str(e)
main()