[mythtv-users] MythArchive 0.27 mythburn.py patch for cutlist support (HD-PVR)

Will Dormann wdormann at gmail.com
Tue Mar 4 03:44:08 UTC 2014


On 3/3/14, 9:27 PM, Will Dormann wrote:
> My prior patch
> <http://www.mythtv.org/pipermail/mythtv-users/2012-October/341879.html>
> did an extra (redundant) pass of transcoding to MPEG2 before proceeding,
> but it seems that this isn't required anymore.


Just to clarify the above statement:
It seems that the extra transcoding pass is indeed required if projectx
isn't used (and mythtranscode is run in its place).  So it's not that
the extra pass isn't required anymore because of a change to
mythburn.py.  But rather that it isn't required when projectx is used.

Because the non-projectx stuff wasn't working quite right, I left the
extra mythtranscode pass (using "newfile3.mpg") out of the patch.

If anybody wants to investigate why the mythtranscode method doesn't
work (if there's a cutlist that removes the beginning of the file), feel
free to try the attached patch.  Though since projectx works, I'm not
sure of the value of that work.  What's the practical difference between
the projectx and mythtranscode methods?   I'm guessing that the latter
is the default just to minimize the reliance on external 3rd party code?


-WD
-------------- next part --------------
--- mythburn.py.orig	2014-03-03 14:13:52.493777354 -0500
+++ mythburn.py	2014-03-03 22:13:51.644342397 -0500
@@ -87,6 +87,7 @@
 import getopt
 import traceback
 import signal
+import subprocess
 import xml.dom.minidom
 from PIL import Image
 from PIL import ImageDraw
@@ -793,7 +794,7 @@
     thumbList = ','.join(thumbList)
 
     if getthumbnails==True:
-        extractVideoFrames( os.path.join(getItemTempPath(itemnum),"stream.mv2"),
+        extractVideoFrames( os.path.join(getItemTempPath(itemnum),"stream.m2v"),
             os.path.join(getItemTempPath(itemnum),"chapter-%1.jpg"), thumbList)
 
     return chapters
@@ -1562,7 +1563,7 @@
 def encodeAudio(format, sourcefile, destinationfile, deletesourceafterencode):
     write( "Encoding audio to "+format)
     if format == "ac3":
-        cmd = "mythffmpeg -v 0 -y "
+        cmd = "ffmpeg -v 0 -y "
 
         if cpuCount > 1:
             cmd += "-threads %d " % cpuCount
@@ -1571,7 +1572,7 @@
         result = runCommand(cmd)
 
         if result != 0:
-            fatalError("Failed while running mythffmpeg to re-encode the audio to ac3\n"
+            fatalError("Failed while running ffmpeg to re-encode the audio to ac3\n"
                        "Command was %s" % cmd)
     else:
         fatalError("Unknown encodeAudio format " + format)
@@ -1686,7 +1687,7 @@
 def getStreamInformation(filename, xmlFilename, lenMethod):
     """create a stream.xml file for filename"""
 
-    command = "mytharchivehelper -q -q --getfileinfo --infile %s --outfile %s --method %d" % (quoteCmdArg(filename), quoteCmdArg(xmlFilename), lenMethod)
+    command = "mytharchivehelper -q --getfileinfo --infile %s --outfile %s --method %d" % (quoteCmdArg(filename), quoteCmdArg(xmlFilename), lenMethod)
 
 
     result = runCommand(command)
@@ -1744,8 +1745,15 @@
         write("Using cutlist: %s" % cutlist_s)
 
     if (localfile != ""):
+        write("Getting cutlist...")
+        result   = subprocess.Popen(['mythutil', '-q', '--getcutlist', '--video', localfile], stdout=subprocess.PIPE).communicate()[0]
+        write("%s" % result)
+        cutlist = string.replace(result,"Cutlist: ", "")
+        cutlist = string.replace(cutlist,"\n", "")
+        splitcutlist = string.split(cutlist,',')
+        cutlist = string.join(splitcutlist,' ')
         if usecutlist == True:
-            command = "mythtranscode --mpeg2 --honorcutlist %s --infile %s --outfile %s" % (cutlist_s, quoteCmdArg(localfile), quoteCmdArg(destination))
+            command = "mythtranscode --mpeg2 --infile %s --outfile %s --honorcutlist \"%s\"" % (quoteCmdArg(localfile), quoteCmdArg(destination), cutlist)
         else:
             command = "mythtranscode --mpeg2 --infile %s --outfile %s" % (quoteCmdArg(localfile), quoteCmdArg(destination))
     else:
@@ -1754,6 +1762,7 @@
         else:
             command = "mythtranscode --mpeg2 --chanid %s --starttime %s --outfile %s" % (chanid, starttime, quoteCmdArg(destination))
 
+    write("Running command %s" % str(command))
     result = runCommand(command)
 
     if (result != 0):
@@ -1769,8 +1778,23 @@
 
 def generateProjectXCutlist(chanid, starttime, folder):
     """generate cutlist_x.txt for ProjectX"""
-
-    rec = DB.searchRecorded(chanid=chanid, starttime=starttime).next()
+    
+    try:
+        rec = DB.searchRecorded(chanid=chanid, starttime=starttime).next()
+    except StopIteration:
+        try:
+            write("Cannot find recording on channel %s at %s. Falling back to filename search." % (chanid, starttime))
+            # Fall back to finding recording by filename
+            streaminfofile = os.path.join(folder, 'streaminfo_orig.xml')
+            streaminfoDOM = xml.dom.minidom.parse(streaminfofile)
+            fileNodes = streaminfoDOM.getElementsByTagName("file")
+            fileNode = fileNodes[0]
+            if fileNode.hasAttribute("filename"):
+                filename = fileNode.attributes["filename"].value
+            rec = DB.searchRecorded(basename=os.path.basename(filename)).next()
+        except StopIteration:
+            fatalError("Failed to get recording details from the DB for %s" % filename)
+        
     starttime = rec.starttime.utcisoformat()
     cutlist = rec.markup.getcutlist()
 
@@ -1803,9 +1827,11 @@
 # Use Project-X to cut commercials and/or demux an mpeg2 file
 
 def runProjectX(chanid, starttime, folder, usecutlist, file):
+    write("running projectx...")
     """Use Project-X to cut commercials and demux an mpeg2 file"""
 
     if usecutlist:
+        write('Using cutlist')
         if generateProjectXCutlist(chanid, starttime, folder) == False:
             write("Failed to generate Project-X cutlist.")
             return False
@@ -1814,7 +1840,8 @@
         write("Error: input file doesn't exist on local filesystem")
         return False
 
-    command = quoteCmdArg(path_projectx[0]) + " %s -id '%s' -set ExternPanel.appendPidToFileName=1 -out %s -name stream" % (quoteCmdArg(file), getStreamList(folder), quoteCmdArg(folder))
+    write('Invoking projectx...')
+    command = quoteCmdArg(path_projectx[0]) + " %s -id '%s' -out %s -name stream" % (quoteCmdArg(file), getStreamList(folder), quoteCmdArg(folder))
     if usecutlist == True:
         command += " -cut %s" % quoteCmdArg(os.path.join(folder, "cutlist_x.txt"))
     write(command)
@@ -1831,46 +1858,11 @@
     if addSubtitles:
         subtitles = selectSubtitleStream(folder)
 
-    videoID_hex = "0x%x" % video[VIDEO_ID]
-    if audio1[AUDIO_ID] != -1:
-        audio1ID_hex = "0x%x" % audio1[AUDIO_ID]
-    else:
-        audio1ID_hex = ""
-    if audio2[AUDIO_ID] != -1:
-        audio2ID_hex = "0x%x" % audio2[AUDIO_ID]
-    else:
-        audio2ID_hex = ""
-    if addSubtitles and subtitles[SUBTITLE_ID] != -1:
-        subtitlesID_hex = "0x%x" % subtitles[SUBTITLE_ID]
-    else:
-        subtitlesID_hex = ""
-
-
-    files = os.listdir(folder)
-    for file in files:
-        if file[0:9] == "stream{0x": # don't rename files that have already been renamed
-            PID = file[7:13]
-            SubID = file[19:23]
-            if PID == videoID_hex or SubID == videoID_hex:
-                os.rename(os.path.join(folder, file), os.path.join(folder, "stream.mv2"))
-            elif PID == audio1ID_hex or SubID == audio1ID_hex:
-                os.rename(os.path.join(folder, file), os.path.join(folder, "stream0." + file[-3:]))
-            elif PID == audio2ID_hex or SubID == audio2ID_hex:
-                os.rename(os.path.join(folder, file), os.path.join(folder, "stream1." + file[-3:]))
-            elif PID == subtitlesID_hex or SubID == subtitlesID_hex:
-                if file[-3:] == "sup":
-                    os.rename(os.path.join(folder, file), os.path.join(folder, "stream.sup"))
-                else:
-                    os.rename(os.path.join(folder, file), os.path.join(folder, "stream.sup.IFO"))
-
-
-    # Fallback if assignment and renaming by ID failed
-
     files = os.listdir(folder)
     for file in files:
-        if file[0:9] == "stream{0x": # don't rename files that have already been renamed
-            if not os.path.exists(os.path.join(folder, "stream.mv2")) and file[-3:] == "m2v":
-                os.rename(os.path.join(folder, file), os.path.join(folder, "stream.mv2"))
+        if file[0:7] == "stream.": # don't rename files that have already been renamed
+            if not os.path.exists(os.path.join(folder, "stream.m2v")) and file[-3:] == "m2v":
+                os.rename(os.path.join(folder, file), os.path.join(folder, "stream.m2v"))
             elif not (os.path.exists(os.path.join(folder, "stream0.ac3")) or os.path.exists(os.path.join(folder, "stream0.mp2"))) and file[-3:] == "ac3":
                 os.rename(os.path.join(folder, file), os.path.join(folder, "stream0.ac3"))
             elif not (os.path.exists(os.path.join(folder, "stream0.ac3")) or os.path.exists(os.path.join(folder, "stream0.mp2"))) and file[-3:] == "mp2":
@@ -2011,13 +2003,13 @@
 # Re-encodes a file to mpeg2
 
 def encodeVideoToMPEG2(source, destvideofile, video, audio1, audio2, aspectratio, profile):
-    """Encodes an unknown video source file eg. AVI to MPEG2 video and AC3 audio, use mythffmpeg"""
+    """Encodes an unknown video source file eg. AVI to MPEG2 video and AC3 audio, use ffmpeg"""
 
     profileNode = findEncodingProfile(profile)
 
     passes = int(getText(profileNode.getElementsByTagName("passes")[0]))
 
-    command = "mythffmpeg"
+    command = "ffmpeg"
 
     if cpuCount > 1:
         command += " -threads %d" % cpuCount
@@ -2077,7 +2069,7 @@
         write(command)
         result = runCommand(command)
         if result!=0:
-            fatalError("Failed while running mythffmpeg to re-encode video.\n"
+            fatalError("Failed while running ffmpeg to re-encode video.\n"
                        "Command was %s" % command)
 
     else:
@@ -2089,7 +2081,7 @@
         result = runCommand(pass1)
 
         if result!=0:
-            fatalError("Failed while running mythffmpeg (Pass 1) to re-encode video.\n"
+            fatalError("Failed while running ffmpeg (Pass 1) to re-encode video.\n"
                        "Command was %s" % command)
 
         if os.path.exists(destvideofile):
@@ -2101,13 +2093,13 @@
         result = runCommand(pass2)
 
         if result!=0:
-            fatalError("Failed while running mythffmpeg (Pass 2) to re-encode video.\n"
+            fatalError("Failed while running ffmpeg (Pass 2) to re-encode video.\n"
                        "Command was %s" % command)
 #############################################################
 # Re-encodes a nuv file to mpeg2 optionally removing commercials
 
 def encodeNuvToMPEG2(chanid, starttime, mediafile, destvideofile, folder, profile, usecutlist):
-    """Encodes a nuv video source file to MPEG2 video and AC3 audio, using mythtranscode & mythffmpeg"""
+    """Encodes a nuv video source file to MPEG2 video and AC3 audio, using mythtranscode & ffmpeg"""
 
     # make sure mythtranscode hasn't left some stale fifos hanging around
     if ((doesFileExist(os.path.join(folder, "audout")) or doesFileExist(os.path.join(folder, "vidout")))):
@@ -2193,7 +2185,7 @@
     samplerate, channels = getAudioParams(folder)
     videores, fps, aspectratio = getVideoParams(folder)
 
-    command =  "mythffmpeg -y "
+    command =  "ffmpeg -y "
 
     if cpuCount > 1:
         command += "-threads %d " % cpuCount
@@ -2221,11 +2213,11 @@
     if (not(doesFileExist(os.path.join(folder, "audout")) and doesFileExist(os.path.join(folder, "vidout")))):
         fatalError("Waited too long for mythtranscode to create the fifos - giving up!!")
 
-    write("Running mythffmpeg")
+    write("Running ffmpeg")
     result = runCommand(command)
     if result != 0:
         os.kill(PID, signal.SIGKILL)
-        fatalError("Failed while running mythffmpeg to re-encode video.\n"
+        fatalError("Failed while running ffmpeg to re-encode video.\n"
                    "Command was %s" % command)
 
 #############################################################
@@ -2472,6 +2464,8 @@
 
     if result<>0:
         fatalError("Failed while running mythreplex. Command was %s" % command)
+        
+    os.rename(os.path.join(folder,"stream.mv2"),os.path.join(folder,"stream.m2v"))
 
 #############################################################
 # Run M2VRequantiser
@@ -2513,7 +2507,7 @@
         #Generate a temp folder name for this file
         folder=getItemTempPath(filecount)
         #Process this file
-        file=os.path.join(folder,"stream.mv2")
+        file=os.path.join(folder,"stream.m2v")
         #Get size of vobfile in MBytes
         totalvideosize+=os.path.getsize(file) 
 
@@ -2554,7 +2548,7 @@
         filecount+=1
         folder=getItemTempPath(filecount)
         progduration=getLengthOfVideo(filecount)
-        file=os.path.join(folder,"stream.mv2")
+        file=os.path.join(folder,"stream.m2v")
         progvsize=os.path.getsize(file)
         progvbitrate=progvsize/progduration
         if progvbitrate>rate : 
@@ -2598,7 +2592,7 @@
         for node in files:
             filecount+=1
             folder=getItemTempPath(filecount)
-            file=os.path.join(folder,"stream.mv2")
+            file=os.path.join(folder,"stream.m2v")
             vsize+=os.path.getsize(file)
             duration+=getLengthOfVideo(filecount)
 
@@ -2634,7 +2628,7 @@
         for node in files:
             filecount+=1
             folder=getItemTempPath(filecount)
-            file=os.path.join(folder,"stream.mv2")
+            file=os.path.join(folder,"stream.m2v")
             progvsize=os.path.getsize(file)
             progduration=getLengthOfVideo(filecount)
             progvbitrate=progvsize/progduration
@@ -2643,9 +2637,9 @@
                 scalefactor=1.0+(fudge_requant*float(progvbitrate-vrate)/float(vrate))
                 if scalefactor>3.0 :
                     write( "Large shrink factor. You may not like the result! ")
-                runM2VRequantiser(os.path.join(getItemTempPath(filecount),"stream.mv2"),os.path.join(getItemTempPath(filecount),"stream.small.mv2"),scalefactor)
-                os.remove(os.path.join(getItemTempPath(filecount),"stream.mv2"))
-                os.rename(os.path.join(getItemTempPath(filecount),"stream.small.mv2"),os.path.join(getItemTempPath(filecount),"stream.mv2"))
+                runM2VRequantiser(os.path.join(getItemTempPath(filecount),"stream.m2v"),os.path.join(getItemTempPath(filecount),"stream.small.m2v"),scalefactor)
+                os.remove(os.path.join(getItemTempPath(filecount),"stream.m2v"))
+                os.rename(os.path.join(getItemTempPath(filecount),"stream.small.m2v"),os.path.join(getItemTempPath(filecount),"stream.m2v"))
     else:
         write( "Unpackaged total %.2f Mb. About %.0f Mb will be unused." % ((allfiles/mega),(mv2space-totalvideosize)/mega))
 
@@ -3241,7 +3235,7 @@
         if node.nodeName=="graphic":
             if node.attributes["filename"].value == "%movie":
                 #This is a movie preview item so we need to generate the thumbnails
-                inputfile = os.path.join(getItemTempPath(videoitem),"stream.mv2")
+                inputfile = os.path.join(getItemTempPath(videoitem),"stream.m2v")
                 outputfile = os.path.join(previewfolder, "preview-i%d-t%%1-f%%2.jpg" % itemonthispage)
                 width = getScaledAttribute(node, "w")
                 height = getScaledAttribute(node, "h")
@@ -4543,8 +4537,8 @@
     #do we need to re-encode the file to make it DVD compliant?
     if not isFileOkayForDVD(file, folder):
         if getFileType(folder) == 'nuv':
-            #file is a nuv file which mythffmpeg has problems reading so use mythtranscode to pass
-            #the video and audio streams to mythffmpeg to do the reencode
+            #file is a nuv file which ffmpeg has problems reading so use mythtranscode to pass
+            #the video and audio streams to ffmpeg to do the reencode
 
             #we need to re-encode the file, make sure we get the right video/audio streams
             #would be good if we could also split the file at the same time
@@ -4607,7 +4601,7 @@
                 profile = defaultEncodingProfile
 
             #do the re-encode 
-            encodeVideoToMPEG2(mediafile, os.path.join(folder, "newfile2.mpg"), video,
+            encodeVideoToMPEG2(mediafile, os.path.join(folder, os.path.basename(file.attributes["filename"].value)), video,
                             audio1, audio2, aspectratio, profile)
             mediafile = os.path.join(folder, 'newfile2.mpg')
 
@@ -4616,6 +4610,19 @@
             if debug_keeptempfiles==False:
                 if os.path.exists(os.path.join(folder, "newfile.mpg")):
                     os.remove(os.path.join(folder,'newfile.mpg'))
+                    
+            if file.attributes["usecutlist"].value == "1" and getText(infoDOM.getElementsByTagName("hascutlist")[0]) == "yes":
+                # Run from local file?
+                localfile = os.path.join(folder, os.path.basename(file.attributes["filename"].value))
+                write("File has a cut list - running mythtranscode to remove unwanted segments")
+                chanid = getText(infoDOM.getElementsByTagName("chanid")[0])
+                starttime = getText(infoDOM.getElementsByTagName("starttime")[0])
+                if runMythtranscode(chanid, starttime, os.path.join(folder,'newfile3.mpg'), True, localfile):
+                  write("mythtranscode success!")
+                  mediafile = os.path.join(folder,'newfile3.mpg')
+                else:
+                  write("Failed to run mythtranscode to remove unwanted segments")
+                mediafile = os.path.join(folder, 'newfile3.mpg')
 
     # the file is now DVD compliant split it into video and audio parts
 
@@ -4649,9 +4656,9 @@
             if usebookmark == True and os.path.exists(previewImage):
                 copy(previewImage, titleImage)
             else:
-                extractVideoFrame(os.path.join(folder, "stream.mv2"), titleImage, thumboffset)
+                extractVideoFrame(os.path.join(folder, "stream.m2v"), titleImage, thumboffset)
         else:
-            extractVideoFrame(os.path.join(folder, "stream.mv2"), titleImage, thumboffset)
+            extractVideoFrame(os.path.join(folder, "stream.m2v"), titleImage, thumboffset)
 
     write( "*************************************************************")
     write( "Finished processing '%s'" % file.attributes["filename"].value)
@@ -4697,8 +4704,8 @@
     #do we need to re-encode the file to make it DVD compliant?
     if not isFileOkayForDVD(file, folder):
         if getFileType(folder) == 'nuv':
-            #file is a nuv file which mythffmpeg has problems reading so use mythtranscode to pass
-            #the video and audio streams to mythffmpeg to do the reencode
+            #file is a nuv file which ffmpeg has problems reading so use mythtranscode to pass
+            #the video and audio streams to ffmpeg to do the reencode
 
             #we need to re-encode the file, make sure we get the right video/audio streams
             #would be good if we could also split the file at the same time
@@ -4818,9 +4825,9 @@
             if usebookmark == True and os.path.exists(previewImage):
                 copy(previewImage, titleImage)
             else:
-                extractVideoFrame(os.path.join(folder, "stream.mv2"), titleImage, thumboffset)
+                extractVideoFrame(os.path.join(folder, "stream.m2v"), titleImage, thumboffset)
         else:
-            extractVideoFrame(os.path.join(folder, "stream.mv2"), titleImage, thumboffset)
+            extractVideoFrame(os.path.join(folder, "stream.m2v"), titleImage, thumboffset)
 
     write( "*************************************************************")
     write( "Finished processing file '%s'" % file.attributes["filename"].value)
@@ -4991,7 +4998,7 @@
                 #Multiplex this file
                 #(This also removes non-required audio feeds inside mpeg streams 
                 #(through re-multiplexing) we only take 1 video and 1 or 2 audio streams)
-                pid=multiplexMPEGStream(os.path.join(folder,'stream.mv2'),
+                pid=multiplexMPEGStream(os.path.join(folder,'stream.m2v'),
                         os.path.join(folder,'stream0'),
                         os.path.join(folder,'stream1'),
                         os.path.join(folder,'final.vob'),
@@ -5006,8 +5013,8 @@
                 for node in files:
                     filecount+=1
                     folder=getItemTempPath(filecount)
-                    if os.path.exists(os.path.join(folder, "stream.mv2")):
-                        os.remove(os.path.join(folder,'stream.mv2'))
+                    if os.path.exists(os.path.join(folder, "stream.m2v")):
+                        os.remove(os.path.join(folder,'stream.m2v'))
                     if os.path.exists(os.path.join(folder, "stream0.mp2")):
                         os.remove(os.path.join(folder,'stream0.mp2'))
                     if os.path.exists(os.path.join(folder, "stream1.mp2")):


More information about the mythtv-users mailing list