Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Video Metadata Question
#1
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
Reply
#2
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.
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#3
(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
Reply
#4
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
Reply
#5
(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.
Reply
#6
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.
Reply
#7
(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'>
Reply
#8
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?
Reply
#9
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.
Reply
#10
3 hours later, I'm throwing in the towel. Over my head. I can't figure out how to find a specific ID...
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
Question image manipulation (cropping and MetaData) SpongeB0B 4 1,167 Jul-03-2023, 06:35 PM
Last Post: SpongeB0B
  AttributeError: 'function' object has no attribute 'metadata 3lnyn0 5 4,646 Mar-28-2022, 04:42 PM
Last Post: Larz60+
  Adding Language metadata to a PDF programmatically bhargavi22 0 1,945 Aug-17-2020, 12:53 PM
Last Post: bhargavi22
  METADATA Errors millpond 0 1,918 Jul-21-2020, 08:22 AM
Last Post: millpond
  How to sort image files according to a metadata file? Brahmslove 1 3,134 Dec-05-2019, 11:25 PM
Last Post: scidam
  Parse the data in XML metadata field klllmmm 2 3,271 Jun-19-2019, 04:24 PM
Last Post: klllmmm
  Tiff metadata sudecki 1 19,695 Aug-10-2018, 07:08 AM
Last Post: sudecki
  I have a question from a YouTube video I saw: nelsonkane 9 5,162 Dec-27-2017, 11:17 PM
Last Post: snippsat

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020