Log in

View Full Version : Can FFMS2 methods be scripted?


markfilipak
10th September 2021, 02:13
Here:
'https://github.com/FFMS/ffms2/blob/master/doc/ffms2-api.md',
I see all the FFMS2 'C' functions.
Which of them have been exposed to CLI scripting?
I'm especially interested in these: FFMS_GetVideoProperties, FFMS_GetAudioProperties, FFMS_GetNumTracks (and, really, all the track methods that can control automation).

:: RELATED ::
In this:
'VapourSynth64/doc/index.html',
I see reference to this:
'VapourSynth64/doc/avfs.html',
that contains a source link to this:
'http://www.turtlewar.org/avfs/'.
Since 'http://www.turtlewar.org/avfs/' appears to be a zombie, I assume that AVFS has been deprecated in favor of FFMS2, correct?

videoh
10th September 2021, 02:39
I assume that AVFS has been deprecated in favor of FFMS2, correct?
Apples and oranges. FFMS2 is a source filter. AVFS is a file system that exposes the output of Avisynth scripts. You could (for example) have FFMS2 as the source filter in a script and then use AVFS to expose that script to an application that does not support VFW.

markfilipak
10th September 2021, 06:03
I assume that AVFS has been deprecated in favor of FFMS2, correct?Apples and oranges. FFMS2 is a source filter. AVFS is a file system that exposes the output of Avisynth scripts. You could (for example) have FFMS2 as the source filter in a script and then use AVFS to expose that script to an application that does not support VFW.
Okay, thanks. What about FFMS2 documentation that goes beyond 'C' functions? Does such documentation exist? Can those functions be scripted? How?

_Al_
10th September 2021, 20:36
I would not try to hack source code plugin to read mediainfo. As running python, you look what is already out there, proper module, that you just load into python script.
You can look here:
https://www.generacodice.com/en/articolo/670413/How-to-get-the-duration-of-a-video-in-Python
there is couple examples how to get duration for a clip, but that is just an example, you can get different properties, there is ffprobe also.
But I use mediainfo utility. There is more than just one method you decide for.

For example just using CLI (command line version of mediainfo.exe (https://mediaarea.net/en/MediaInfo/Download/Windows)) and subprocess in python,example, where you get all mediainfo data in data dictionary:

import subprocess
import json

source = r'F:/my_video.mp4' #directly using source, not vapoursynth clip

cmd = '"C:/tools/MediaInfo_CLI_21.03_Windows_x64/MediaInfo.exe"'
cmd += ' --Output=JSON'
cmd += f' "{source}"'
proc = subprocess.Popen(cmd, shell=True,stderr=subprocess.PIPE, stdout=subprocess.PIPE)
stdout, stderr = proc.communicate()
data = json.loads(stdout) #conversion from stdout, that is json format, to python's dictionary object
#print(json.dumps(data, indent=2)) #use this, it prints pretty, formatted, to orient yourself in that dictionary
audio_count = data['media']['track'][0]['AudioCount'] #that slice [0] means general section
video_count = data['media']['track'][0]['VideoCount']
print('#of video tracks=',video_count,' #of audio tracks=',audio_count)

Or you can use this, more manual approach to design dictionaries yourself and then just fill properties using mediainfo.dll (https://mediaarea.net/en/MediaInfo/Download/Windows) (not exe) having in working directory and using MediaInfoDLL3.py (google it), never tried to check linux mediainfo (https://mediaarea.net/en/MediaInfo/Download/Ubuntu) , two *.deb files ?, just mediainfo.dll on windows but it should work also:
use this as a module, name it for example my_mediainfo.py:

from MediaInfoDLL3 import *

class Media:
v = { 'Format': '',
'Width': '',
'Height':'',
'ScanType':'',
'ScanOrder': '',
'FrameRate': '',
'FrameRate_Num': '',
'FrameRate_Den': '',
'FrameRate_Mode': '',
'FrameRate_Minimum': '',
'FrameRate_Maximum': '',
'DisplayAspectRatio/String': '',
'ColorSpace': 'YUV',
'ChromaSubsampling': '',
'BitDepth': '',
'Duration': '',
'Duration/String3': ''}

c = { 'colour_range': '',
'colour_description_presen': '',
'colour_primaries': '',
'transfer_characteristics': '',
'matrix_coefficients': '',
'colour_primaries_Original': '',
'transfer_characteristics_':'',
'matrix_coefficients_Origi':''}

a = { 'Format': '',
'BitRate': '',
'BitRate_Mode': '',
'Channel(s)': '',
'SamplingRate': '',
'BitDepth': ''}

color_dict = {'Color Range' : 'colour_range',
'Color Discription' : 'colour_description_presen',
'Matrix Coefitients' : 'matrix_coefficients',
'Matrix Coefitients Original': 'matrix_coefficients_Origi',
'Color Primaries' : 'colour_primaries',
'Color Primaries Original' : 'colour_primaries_Original',
'Transfer Characteristics' : 'transfer_characteristics'}


def __init__(self):
super(Media, self).__init__()
pass


def mediainfo(self, video_path):

if not video_path:
return

MI = MediaInfo()
MI.Open(video_path)

try: self.v_count = int(MI.Get(Stream.General, 0, "VideoCount"))
except: self.v_count = 0
try: self.a_count = int(MI.Get(Stream.General, 0, "AudioCount"))
except: self.a_count = 0

for stream in range(0,self.v_count):
self.v['format']=''
for key in self.v:
value = MI.Get(Stream.Video, stream, key)
self.v[key] = value
for key in self.c:
value = MI.Get(Stream.Video, stream, key)
self.c[key] = value
if self.v['Format']:
pass

for stream in range(0,self.a_count):
self.a['format']=''
for key in self.a:
value = MI.Get(Stream.Audio, stream, key)
self.a[key] = value
if self.a['Format']:
pass

MI.Close()

return self.v, self.c, self.a
and just use it in your script:
import my_mediainfo as m
import json #just needed for pretty print
source = r'E:\my_video.mp4'
mi = m.Media()
videos, colors, audios = mi.mediainfo(source)
print(json.dumps(videos, indent=2))
print(json.dumps(colors, indent=2))
print(json.dumps(audios, indent=2))
print will show you:
{
"Format": "AVC",
"Width": "1920",
"Height": "1080",
"ScanType": "Progressive",
"ScanOrder": "",
"FrameRate": "59.940",
"FrameRate_Num": "60000",
"FrameRate_Den": "1001",
"FrameRate_Mode": "CFR",
"FrameRate_Minimum": "",
"FrameRate_Maximum": "",
"DisplayAspectRatio/String": "16:9",
"ColorSpace": "YUV",
"ChromaSubsampling": "4:2:0",
"BitDepth": "8",
"Duration": "4972",
"Duration/String3": "00:00:04.972",
"format": ""
}
{
"colour_range": "Limited",
"colour_description_presen": "",
"colour_primaries": "BT.709",
"transfer_characteristics": "BT.709",
"matrix_coefficients": "BT.709",
"colour_primaries_Original": "",
"transfer_characteristics_": "",
"matrix_coefficients_Origi": ""
}
{
"Format": "AAC",
"BitRate": "264600",
"BitRate_Mode": "CBR",
"Channel(s)": "2",
"SamplingRate": "48000",
"BitDepth": "",
"format": ""
}
I just simplified this from more elaborate version, those dictionaries will be only for last tracks loaded, but you can fix it. Or something else might not work, but you get the idea.