Python programming for DSLR

It has been almost 5 years since I shot my first commercial with Red Epic. In those years shooting 4k raw video felt crazy as 4k and raw were just at the doors of the industry. Before Red’s arrival I only worked with scanned 35mm film and the only raw format I used was Canon’s CR2 photo format. Since I haven’t had any experience with digital raw video my expectations were really high as Red’s marketing and advertisement made me believe that digital raw video was a paramount of a beautiful image. In the end it turned out to be partly true with some compromises and limitations. When Magic Lantern announced that the 5d mark 3 might be able to shoot raw video, I understood that the high-end video would be accessible to anyone who owns the Canon DSLR.

Nowadays, the 5d mark 3 with the Magic Lantern add-on can output raw video stream into a proprietary video format called MLV. MLV is a 14 bit raw video file. Despite being powerful format which contains crazy amount of data directly from a sensor of the camera, the format is not readable by most of commercial editing and grading suits. That is why I decided to write a python app which converts the MLV format to standard DNGs.

MLV_convert

The app’s GUI and folder structures of the processed DNGs

The converter is written in Python 3.4 and wraps around mlv_dump tool. I wanted the converter to use Python’s Object Oriented Programming for future developments and multithreading use. The current version, which I wrote in 2014, is single threaded thus the conversion process of a large amount of video may take a while. The program converts and organizes the resulted DNG files in folder structures that best fit my workflow.After the conversion, the DNGs are brought to Resolve for the First Light grading and transcoding to NLE friendly video format, just like good old days of 35mm film workflow.Here are some stills from the 4k music video I’ve shot with my 5d mark III and Magic Lantern Addon.

log3

The digital negative from the ML converter

Rec.709

The DNG converted to Rec.709 with some grading applied

And finally here is the python code of the ML converter. The code relies on Python’s native libraries. Fill free to use and mod it for your own needs.

#title                     :ML_convert 
#version                   :1.0
#description               :The app converts MLV files to a DNG sequence. 
#usage                     :In order to use ML_convert, 
#                          copy MLV_DUMP tool to Win C:/Program Files/ or Mac /usr/local/bin
#date                      :July 22 2014 
#python_version            :3.4
#note                      :MLV_DUMP tool can be downloaded 
#                          for free from Magic Lantern's website.

import os
import shutil
from tkinter import *
from tkinter.filedialog import askopenfilenames 

class ml_converter:
    p = ''
    exe = ''
    winexe = 'C:/Program Files/mlv_dump.exe'
    macexe = '/usr/local/bin/mlv_dump.osx'
    testexe = 'C:/mlv_dump.exe'
    result = ''
    
    def find_mlv_dump(self):
        self.exe = self.winexe
        if not os.path.isfile(self.winexe):
            self.exe = self.macexe
        if os.path.isfile(self.exe):
            return True
        else:
            return False
        
    def convert(self,mlv_file):
        #dir = os.path.dirname(mlv_file)
        ext = os.path.splitext(mlv_file)[-1].lower()
        if ext==".mlv":
            direct,f = os.path.split(mlv_file)
            filename = f[:-4]
            newdir = (direct+("/"+filename))
            if not os.path.exists(newdir):
                os.mkdir(newdir)
                newdir = shutil.move(mlv_file,newdir)
            else:
                print ("Directory already exists,the file moved into already existing folder")
                newdir = shutil.move(mlv_file,newdir)
            os.system("\""+"\""+ self.exe+"\"" + ' --dng' + " \""+ newdir +"\""+"\"")
            shutil.move(newdir,mlv_file)
            self.result = 1
            return self.result
        else:
            print (" not supported file format")
            self.result = 0
            return self.result
        

class ml_ui(Frame, ml_converter):
    def __init__(self,mlc):
        Frame.__init__(self)
        self.mlv_files = []
        self.mlv_file = ''
        self.str = ''
        self.exe = 1
        self.result = ''
        self.i = 0
        self.master.title("MLV convert")
        self.pack()
        self.browse_btn = Button(self, text="Browse MLV", command=self.load_file, width=20)
        self.browse_btn.pack(side = "top")
        self.convert_btn = Button(self,text="Convert to DNG",command=lambda: self.conv(), width=20)
        self.convert_btn.pack(side = "top")
        self.log = Text(self)
        self.log.pack(side="top")

    def load_file(self):
        self.mlv_files = askopenfilenames() 
    def conv(self):
        self.exedir = self.find_mlv_dump()
        if self.exedir ==True:
            self.i = 0
            size = len(self.mlv_files)
            print (size)
            self.log.delete('1.0',END)
            for self.mlv_file in self.mlv_files:
                self.result = self.convert(self.mlv_file)
                self.i+=1
                if (self.result != 0):
                    self.log.insert(INSERT,str(self.mlv_file)+"    Done!"+"\n") #### fix needed, UI shows non MLV files processed
                    self.str = '%i out of %i \n'%(self.i,size)
                    self.log.insert(INSERT,self.str)
                    self.log.see(END)
                    ml_ui.update(self)

                else:
                    self.log.insert(INSERT,str(self.mlv_file)+" is not MLV file!"+"\n")
                    self.str = '%i out of %i \n'%(self.i,size)
                    self.log.insert(INSERT,self.str)
                    self.log.see(END)
                    ml_ui.update(self)
        else:
            self.log.insert(INSERT," MLV_DUMP program is not found \n Copy the MLV_DUMP into C:/Program Files/ or /usr/local/bin \n" )
            print('not found')

if __name__ == "__main__":
    mlc = ml_converter()
    ui = ml_ui(mlc)
    ui.mainloop()
        

 

Leave a Reply

The reply will be processed within a day