Posts: 131
Threads: 35
Joined: Apr 2018
I am wondering if there is a way to get certain metadata out of a video file (MKV specifically) without the use of third-party modules? If not, what would you all use for scripts that need to access metadata from a video file? I'm looking for video dimensions.
Thanks,
malonn
Posts: 2,021
Threads: 9
Joined: May 2017
If you want to write your own parser, yes it's possible.
Here is the specification: https://matroska.org/technical/specs/index.html
You'll need the module struct to work with binary data.
Posts: 7,087
Threads: 122
Joined: Sep 2016
(Jul-20-2018, 03:53 PM)malonn Wrote: what would you all use for scripts that need to access metadata from a video file? I'm looking for video dimensions. Would use FFmpeg or more specialized tools for metadata like MediaInfo, ExifTool.
There are some wrapper for this tools if search PyPi,
but last time a looked at this i think 1-2 ago many of this tool is outdated or Python 2 only.
It easy to use say FFmpeg to get video dimensions.
ffmpeg -i your.mkv -hide_banner
# Or Mediainfo here get all metadata
mediainfo --Full your.mkv Eg output FFmpeg:
Output: λ ffmpeg -i planet.mkv -hide_banner
Input #0, matroska,webm, from 'planet.mkv':
Metadata:
ENCODER : Lavf57.75.100
Duration: 00:49:48.09, start: 0.000000, bitrate: 2418 kb/s
Stream #0:0: Video: h264 (High), yuv420p(progressive), 1280x720 [SAR 1:1 DAR 16:9], 25 fps, 25 tbr, 1k tbn, 50 tbc (default)
Metadata:
VARIANT_BITRATE : 0
DURATION : 00:49:48.085000000
Stream #0:1: Audio: ac3, 48000 Hz, stereo, fltp, 192 kb/s (default)
Metadata:
VARIANT_BITRATE : 0
ENCODER : Lavc57.100.103 ac3
DURATION : 00:49:47.968000000
So can write quick wrapper example with subprocess.
from subprocess import Popen, PIPE
import re
video_file = 'planet.mkv'
res = Popen(['ffmpeg', '-i', video_file, '-hide_banner'],stdout=PIPE,stderr=PIPE)
none,meta = res.communicate()
meta_out = meta.decode()
#---| Take out info
duration = re.search(r'Duration:.*', meta_out)
print(duration.group())
size = re.search(r'\d{3,4}x\d{2,3}', meta_out)
print(size.group()) Output: Duration: 00:49:48.09, start: 0.000000, bitrate: 2418 kb/s
1280x720
Posts: 131
Threads: 35
Joined: Apr 2018
Thanks for the responses @ DeaD_EyE & @ snippsat. I'd like to avoid third-party apps if possible (though it's the easier route), so I guess I'll try writing a simple parser(?). Is there such a thing as a "simple" one?
I've never done anything with binary data in Python, but the docs and forums are here, as well as Google, so I'll see what I can do.
Thanks for the assist,
malonn
Posts: 7,087
Threads: 122
Joined: Sep 2016
Jul-20-2018, 09:51 PM
(This post was last modified: Jul-20-2018, 09:51 PM by snippsat.)
(Jul-20-2018, 08:35 PM)malonn Wrote: so I guess I'll try writing a simple parser(?). Is there such a thing as a "simple" one?
I've never done anything with binary data in Python Then the simplicity goes out the windows,if try to do this from the binary data.
If want to it as a excises with .mkv files look at specifications @ DeaD_EyE posted.
Can try to just find video dimensions to see how that goes.
Can look at eyeD3 that dos this from mp3 files.
There will find many places file read eg tag.py.
mode = "rb+" if os.path.isfile(self.file_info.name) else "w+b"
with open(self.file_info.name, mode) as tag_file:
# Write the tag over top an original or append it.
try:
tag_file.seek(-128, 2)
if tag_file.read(3) == b"TAG":
tag_file.seek(-128, 2)
else:
tag_file.seek(0, 2)
except IOError:
# File is smaller than 128 bytes.
tag_file.seek(0, 2)
tag_file.write(tag)
tag_file.flush() As excepted the file get read in binary rb ,the try to figure how to navigate/search the binary date to get to the needed metadata.
Posts: 131
Threads: 35
Joined: Apr 2018
Thanks for the info, @ snippsat. I've Googled some and perused the docs some but am quite confused honestly. I found this online:
mkvparse, but it's quite a bit more complicated than I need. I'll keep trying to make heads and tails of it, but in the mean time let me ask this: the basic approach I need is to open the file in binary mode and read a certain amount of bytes, right? Then search those bytes for what I'm looking for (dimensions)? The mkv docs assume you have the programming under control (which I do not), but they have the info I need.
I don't even have code yet to share. But once I do, I'll post it here.
Posts: 7,087
Threads: 122
Joined: Sep 2016
Jul-21-2018, 12:41 AM
(This post was last modified: Jul-21-2018, 12:46 AM by snippsat.)
(Jul-20-2018, 11:23 PM)malonn Wrote: the basic approach I need is to open the file in binary mode and read a certain amount of bytes, right? That's a start,read some data let say 1000 bytes at time and look at the data.
Example.
with open('planet.mkv', 'rb') as f:
data = f.read()[:1000]
print(data) When doing this test i can see that some of the meta data is in clear text.
To take of some data.
import re
with open('planet.mkv', 'rb') as f:
data = f.read()[:3000]
#print(data)
rate = re.search(b'bitrate=\d+', data)
print(rate.group())
vbv_max = re.search(b'vbv_maxrate=\d+', data)
print(vbv_max.group()) Output: b'bitrate=2250'
b'vbv_maxrate=2812'
From bytes to string(this Unicode bye default) in Python 3.
>>> b = b'bitrate=2250'
>>> type(b)
<class 'bytes'>
>>> s = b.decode() # same as decode('utf-8')
>>> s
'bitrate=2250'
>>> type(s)
<class 'str'>
Posts: 131
Threads: 35
Joined: Apr 2018
Jul-21-2018, 01:26 AM
(This post was last modified: Jul-21-2018, 01:26 AM by malonn.)
This is the output I get from reading the first 1K of a 25GB MKV:
Output: [Dbg]>>>
b'\x1aE\xdf\xa3\xa3B\x86\x81\x01B\xf7\x81\x01B\xf2\x81\x04B\xf3\x81\x08B\x82\x88matroskaB\x87\x81\x02B\x85\x81\x02\x18S\x80g\x01\x00\x00\x04\xb8d\xd3\x86\x11M\x9bt\xfeM\xbb\x92S\xab\x84\x15I\xa9fS\xac\x88\x00\x00\x00\x00\x00\x00\x04\x83M\xbb\x92S\xab\x84\x16T\xaekS\xac\x88\x00\x00\x00\x00\x00\x00\x05\x16M\xbb\x92S\xab\x84\x1cS\xbbkS\xac\x88\x00\x00\x00\x04\xb8b\xb5\x87M\xbb\x92S\xab\x84\x10C\xa7pS\xac\x88\x00\x00\x00\x00\x00\x00\x06u\xec\x93\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00M\xbb\x92S\xab\x84\x12T\xc3gS\xac\x88\x00\x00\x00\x04\xb8d\xce\xb6\xecC\xfd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
and it took forever to output that. There has to be a better way. You have given me other ways though, @ snippsat. I'm going to try a thing or two and see what's what...
EDIT:
Okay, I can fix the slowness of the file by reading 1K at a time, not loading the entire file. 16 Gigs of memory and a 25 Gig file makes for a slow computer, hehe. But I appreciate your help, @ snippsat, but I don't think this is the way to go. I need to use the EBML format in the files, but don't have a clue how to do that. Google results just confuse me. Maybe I need to search for more about EBML itself?
Posts: 131
Threads: 35
Joined: Apr 2018
Alright. Progress has been made. I have discovered that the EBML format used by MKV's starts at the beginning of the file (don't laugh, I'm the most noob of noobs). So, I have been able to locate the EBML starter using the following code:
with open('D:\\Rampage_t01.mkv', 'rb') as f:
cur_size = os.stat('D:\\Rampage_t01.mkv').st_size
w = 0
p = f.read(1)
pp = ord(p)
print(struct.unpack('>L', p + f.read(3))[0]) This returns 440786851 or 1A45DFA3 in hex, which is what all Matroska EBML code starts with. I didn't know that the info (it makes sense to me though) about the MKV would be found at the beginning of the file. Now, I believe, I just need to walk through the MKV until I find the ID I'm interested in and read it's info. That's the plan; a long way to go, but it's a plan.
So, that's that. I'll post back as I make progress.
Posts: 131
Threads: 35
Joined: Apr 2018
3 hours later, I'm throwing in the towel. Over my head. I can't figure out how to find a specific ID...
|