2

I would like to standardize my video collection on a specific video codec (for instance the x265 High Efficiency Video Codec). I know I can obtain the codec in use from a single file using for instance 'mediainfo filename | grep "Codec ID"' Which will output the video codec followed by the audio codec for each file like:

Codec ID                                 : V_VP8
Codec ID                                 : A_VORBIS

I've reviewed man find but I can't seem to figure out how to accomplish this. Any ideas?

0

4 Answers 4

6

A combination of find, ffprobe, jq utilities could be used to print info about all *.avi, *.mp4 files (in the current directory tree recursively) that are NOT encoded using "h264" video codec:

$ find -name \*.avi -o -name \*.mp4 \
    -exec ffprobe -v quiet -show_streams -show_format -of json {} \; |
  jq -c '.format.filename as $path |
         .streams[]? |
         select(.codec_type=="video" and .codec_name!="h264") |
         {codec: .codec_name, path: $path}'

To install the utilities, run:

$ sudo apt-get install ffmpeg jq findutils

The example works on jq 1.4. If apt-get version provides an older version; you could download a newer jq binary (just put the downloaded file somewhere in $PATH, rename it to jq and make it executable: chmod +x jq).

10
  • for some reason I get no output whatsoever after changing -name parameter to those I actually have (*.mkv) although there are many files that are not h264. However if I change "h264" to "hevc" I find 2 h264 files.
    – Elder Geek
    Jun 5, 2016 at 13:16
  • @ElderGeek: 1- I've suppressed "jq: error: Cannot iterate over null" message (it means ffprobe has not found any streams in the input file). 2- this command prints only those video files that are NOT encoded using h264 (!=).¶ There are three parts: find, ffprobe, and jq: I recommend to debug them separately i.e., first make sure that find finds the necessary files then ensure that ffprobe can extract the code info from a given video file then use jq to filter the ffprobe output.
    – jfs
    Jun 5, 2016 at 13:17
  • both find and ffprobe appear to work as advertised.
    – Elder Geek
    Jun 5, 2016 at 13:29
  • @ElderGeek: save the ffprobe's output in a file input.json, feed it to your jq command, save it to the output.json file then if output.json is not what you want then provide the desired output and post all that info (input.json, output.json, desired_output.json, the complete jq command that you use as a separate question).
    – jfs
    Jun 5, 2016 at 13:34
  • for some reason I couldn't get the -or switch to work in this context I did get reasonable output using find -name \*.mkv -exec ffprobe -v quiet -show_streams -show_format -of json {} \; | jq -c '.format.filename as $path | .streams[] | select(.codec_type=="video" and .codec_name!="hevc") | {codec: .codec_name, path: $path}'
    – Elder Geek
    Jun 5, 2016 at 16:02
1

You can get a sorted list of your codec specific media files under the working directory by

$ mediainfo * | grep -v codec_id | grep .file_extension | cut -f2 -d: > list.txt

where codec_id is the codec in question (ex. h264) and file_extension is the extension of the container in question (ex. .mkv)

but if the file names have blank spaces between names then the command will not work as desired.

0
1

You can use this small python script together with find to print all files with specific codec:

filterByCodec.py

import os
import sys
import json

inputPath = sys.argv[1]
codec = sys.argv[2]
type = sys.argv[3]

cmd = 'ffprobe -v quiet -show_streams -print_format json ' + inputPath
output = os.popen(cmd).read()
output = json.loads(output)

if not 'streams' in output:
    sys.exit(0)
for stream in output['streams']:
    if stream['codec_name'] == codec and stream['codec_type'] == type:
        print inputPath
        sys.exit(0)

This will call ffprobe, store its output in json string, iterate over all streams and print the input path in case codec name and type match. You will need ffprobe for this. You can get it as a static build from here if you don't have it installed on your system.

Then you can call it on every file using find like this:

find . -type f -exec python filterByCodec.py {} hevc video \;

this will print all videos containing HEVC video codec. More examples:

find . -type f -exec python filterByCodec.py {} h264 video \;
find . -type f -exec python filterByCodec.py {} mp3 audio \; 

You can extend the script and move those files into some directory or whatever. This could look something like this:

cmd = 'mv ' + inputPath + ' onlyhevcDir'
os.system(cmd)

I know that this is not the best way to do it, but using python it's pretty simple to do.

7
  • Where does python expect to find the script? I get python: can't open file 'filterByCodec.py': [Errno 2] No such file or directory
    – Elder Geek
    Jun 5, 2016 at 13:38
  • @ElderGeek in the same directory where you run find. But you can copy it either in /usr/local/bin or export path to enable access to it from everywhere Jun 5, 2016 at 13:42
  • Thank you stackoverflow.com/questions/23915661/… explains it.
    – Elder Geek
    Jun 5, 2016 at 13:43
  • I got it working by specifying the full path to the script. for some reason just having it on the path or in /usr/local/bin didn't work for me.
    – Elder Geek
    Jun 5, 2016 at 14:05
  • @ElderGeek I'm sorry my previous comment is complete bullshit, putting it to your path can not tell python where to find the script (since its not a executable what we are searching for, its just a script), so providing the full absolute path to script like you did is the best way to do it I guess. Jun 5, 2016 at 14:23
0

fix issue with spaces by replacing

cmd = 'ffprobe -v quiet -show_streams -print_format json ' + inputPath

with

cmd = 'ffprobe -v quiet -show_streams -print_format json ' + "\"" + inputPath + "\""

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .