<br><br><div class="gmail_quote">On Wed, Jan 11, 2012 at 11:13 AM, Jeremy Jones <span dir="ltr">&lt;<a href="mailto:jeremy.dwain.jones@gmail.com">jeremy.dwain.jones@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br><br><div class="gmail_quote"><div class="im">On Wed, Jan 11, 2012 at 10:26 AM, Josh Rosenberg <span dir="ltr">&lt;<a href="mailto:mythtv@desh.info" target="_blank">mythtv@desh.info</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">


All,<br>
<br>
I&#39;m still struggling a lot with setting up transcoding.  But rather<br>
than ask for specific help, I&#39;m going to try a different approach.<br>
<br>
Those of you who do any sort of lossy or format-converting transcoding<br>
beyond just stripping commercials, share how you do it!  Built-in<br>
transcoding, a user job, or what?  </blockquote><div><br></div></div><div>I am transcoding to mpeg-2 standard definition (480p) from High Definition content.  This cannot be done with built-in transcoders, because anything that changes the resolution makes the container a nuv (nupple Video file).  So I asked a similar question.  you can find the thread by googling, &quot;mythtv Replacing mythtranscode command with a custom script&quot;.   But to make a long thread short, I ended up using the &quot;transcode wrapper stub&quot; from the wiki <a href="http://www.mythtv.org/wiki/Transcode_wrapper_stub" target="_blank">http://www.mythtv.org/wiki/Transcode_wrapper_stub</a>, which will take care of replacing the original file and everything for you after transcoding.  The stub just needs your transcode command added to it.  I&#39;ll post mine tonight as a follow up to this thread, but until then there is at least one example called, &quot; Low Quality Transcode&quot; on the wiki <a href="http://www.mythtv.org/wiki/Low_Quality_Transcode" target="_blank">http://www.mythtv.org/wiki/Low_Quality_Transcode</a>.  </div>
<div class="im">
<div><br></div>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">If you use a script someone posted<br>
online, have you modified it?  If you use a standard utility like<br>
ffmpeg, </blockquote><div><br></div></div><div>I am using ffmpeg from within the stub.</div><div class="im"><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
or a script with multiple modes, what options do you call it<br>

with?  </blockquote><div><br></div></div><div>No multiple modes in mine.  I call mine by replacing the built-in transcoder, but it can be run as a user job.  I chose to replace it, so that I could have the transcodeing run before commercial flagging.  </div>
<div class="im">
<div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Also, how long does the conversion take and how well does it<br>
work for you (that is, how much space does it save and how is the<br>
quality impacted)?<br></blockquote><div><br></div></div><div>Saves a lot of space, but yes quality is impacted, since I am actually changing (for compatibility with a network player) to Standard Definition instead of High Definition.  Regardless of that, I would still recommend using Raymonds wrapper for whatever your setting are.  Other posters may have more fitting information on ffmpeg settings. (or mencoder, or handbrake)  It just need to be able to be executed from a cli for the stub to use it.</div>
<div class="im">
<div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Bonus points for explaining why you chose what you chose, or what<br>
alternatives you&#39;ve discarded along the way.<br></blockquote><div><br></div></div><div>I chose to use ffmpeg because I already had it and it seems to be very popular.  I just google for settings that other users had and tried different variations until I got output that worked with my network player.  Once I had that I wrote a script and called it as a user job.  I had problems though swapping out the files.  The end result had the mythtv file and the transcoded one.  I had something that was working, but it was not consistent and actually returned errors in mythtv.  Then I discovered the wrapper stub, and it made everything easier.  I just abandoned my script and put my ffmpeg command into that new script and ran it as the user job.  </div>

<div><br></div><div>Then I discovered that the commercial skip wasn&#39;t working and so I asked questions here. Turns out the commercial flags are frame specific and if your transcoding changes frames, then the flags are no good.  So I now had to run a second user job to flag the commercials.  In getting help on setting that up someone pointed me to actually changing the mythtv transcode  command.  I posted asking fo help doing that.  See the thread starting here: <a href="http://www.gossamer-threads.com/lists/mythtv/users/490927?do=post_view_threaded#490927" target="_blank">http://www.gossamer-threads.com/lists/mythtv/users/490927?do=post_view_threaded#490927</a></div>
<div class="im">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Google searching for transcode help seems to mostly reveal people who<br>
are struggling, and I&#39;d like to hear some examples from people who are<br>
succeeding!  Regardless of whether your use case exactly matches mine<br>
or not.<br>
<br>
Thanks!<br>
<br>
Josh<br><br></blockquote></div><div>Like I said, I will post my entire script tonight when I have access to my computer.  </div><span class="HOEnZb"><font color="#888888"><div><br></div><div>Jeremy</div><div><br></div><div>
 </div></font></span></div></blockquote><div><br></div><div>As promised I copied the script below and attached it, but I am not sure if attaching files works or is acceptable here.  I run this for all recordings that I transcode, so I just replaced &#39;joQueueTranscodeCommand&#39; with &#39;/home/username/DVDtranscode.py %JOBID%&#39;  It can be called just as easily as a user job though.</div>
<div><br></div><div>The script is based on the the transcode wrapper stub on the wiki.  I would recommend starting with the one on the wiki and adding your own command for &quot;output&quot;.  Raymond has plenty of good comments in there for what you need to change and/or add. I added some lines to mine that I thought would help me troubleshoot some things, but I don&#39;t know if they really do anything or not.  That is why I don&#39;t recommend starting with mine.  Just use it as an example.  As you can see I am using ffmpeg to do the transcoding and the command I use is there in the script.  FFMPEG is pretty well documented and pretty customize-able on what you want to do, but post back for help if you need it.  I&#39;ll share the little that I have learned about it, and I&#39;m sure there are others who can be of *much* better help here too.</div>
<div><br></div><div>Jeremy</div><div><br></div><div><br></div><div><br></div><div>Finlename: DVDtranscode.py</div><div><br></div><div>code begins below the line:</div><div>-------------------------------------------------</div>
<div>#!/usr/bin/env python</div><div><br></div><div>from MythTV import Job, Recorded, System, MythDB, findfile, MythError</div><div><br></div><div>from optparse import OptionParser</div><div>import sys</div><div>import os</div>
<div><br></div><div>################################</div><div>#### adjust these as needed ####</div><div>transcoder = &#39;/usr/bin/ffmpeg&#39;</div><div>flush_commskip = False</div><div>build_seektable = False</div><div>
################################</div><div><br></div><div>def runjob(jobid=None, chanid=None, starttime=None):</div><div>    db = MythDB()</div><div>    job = Job(jobid, db=db)</div><div>    chanid = job.chanid</div><div>
    starttime = job.starttime</div><div>    rec = Recorded((chanid, starttime), db=db)</div><div>    if jobid:</div><div>        job.update({&#39;status&#39;:4, &#39;comment&#39;:&#39;Running as %jobid&#39;})</div><div><br>
</div><div>    sg = findfile(rec.basename, rec.storagegroup, db=db)</div><div>    if sg is None:</div><div>        if jobid:</div><div>            job.update({&#39;status&#39;:4, &#39;comment&#39;:&#39;Local access to recording not found.&#39;})</div>
<div>        print &#39;Local access to recording not found.&#39;</div><div>        sys.exit(1)</div><div><br></div><div>    infile = os.path.join(sg.dirname, rec.basename)</div><div>    outfile = &#39;%s.mpeg&#39; % infile.rsplit(&#39;.&#39;,1)[0]</div>
<div>    #### list of segments to be cut</div><div>    # rec.markup.gencutlist()</div><div>    #### list of segments to keep</div><div>    # rec.markup.genuncutlist()</div><div>    if jobid:</div><div>        job.update({&#39;status&#39;:4, &#39;comment&#39;:&#39;starting ffmpeg&#39;})</div>
<div>  </div><div>    task = System(path=transcoder, db=db)</div><div>    try:</div><div>##############################################</div><div>#### probably need to adjust this one too ####</div><div>        output = task(&#39;-y -i &quot;%s&quot; -target ntsc-dvd -async 1 &quot;%s&quot; 2&gt; /dev/null &#39; % (infile, outfile) )</div>
<div>##############################################</div><div>        if jobid:</div><div>            job.update({&#39;status&#39;:4, &#39;comment&#39;:&#39;ffmpeg complete&#39;})</div><div>    except MythError, e:</div><div>
        if jobid:</div><div>            job.update({&#39;status&#39;:8, &#39;comment&#39;:&#39;ffmpeg threw an error&#39;})</div><div>        print &#39;Command failed with output:\n%s&#39; % e.stderr</div><div>        sys.exit(e.returncode)</div>
<div><br></div><div>    rec.basename = os.path.basename(outfile)</div><div>    os.remove(infile)</div><div>    rec.filesize = os.path.getsize(outfile)</div><div>    rec.transcoded = 1</div><div>    rec.seek.clean()</div><div>
    </div><div>    if jobid:</div><div>        job.update({&#39;status&#39;:4, &#39;comment&#39;:&#39;Removed old File&#39;})</div><div><br></div><div>    if flush_commskip:</div><div>        for index,mark in reversed(list(enumerate(rec.markup))):</div>
<div>            if mark.type in (rec.markup.MARK_COMM_START, rec.markup.MARK_COMM_END):</div><div>                del rec.markup[index]</div><div>        rec.bookmark = 0</div><div>        rec.cutlist = 0</div><div>        rec.markup.commit()</div>
<div>        if jobid:</div><div>            job.update({&#39;status&#39;:4, &#39;comment&#39;:&#39;Comm_Flushed&#39;})</div><div><br></div><div>    if build_seektable:</div><div>        task = System(path=&#39;mythcommflag&#39;)</div>
<div>        task.command(&#39;--chanid %s&#39; % chanid,</div><div>                     &#39;--starttime %s&#39; % starttime,</div><div>                     &#39;--rebuild&#39;)</div><div>        if jobid:</div><div>            job.update({&#39;status&#39;:4, &#39;comment&#39;:&#39;rebuilt seektable&#39;})</div>
<div><br></div><div>    rec.update()</div><div><br></div><div>    if jobid:</div><div>        job.update({&#39;status&#39;:272, &#39;comment&#39;:&#39;Transcode Completed&#39;})</div><div><br></div><div>def main():</div><div>
    parser = OptionParser(usage=&quot;usage: %prog [options] [jobid]&quot;)</div><div><br></div><div>    parser.add_option(&#39;--chanid&#39;, action=&#39;store&#39;, type=&#39;int&#39;, dest=&#39;chanid&#39;,</div><div>            help=&#39;Use chanid for manual operation&#39;)</div>
<div>    parser.add_option(&#39;--starttime&#39;, action=&#39;store&#39;, type=&#39;int&#39;, dest=&#39;starttime&#39;,</div><div>            help=&#39;Use starttime for manual operation&#39;)</div><div>    parser.add_option(&#39;-v&#39;, &#39;--verbose&#39;, action=&#39;store&#39;, type=&#39;string&#39;, dest=&#39;verbose&#39;,</div>
<div>            help=&#39;Verbosity level&#39;)</div><div><br></div><div>    opts, args = parser.parse_args()</div><div><br></div><div>    if opts.verbose:</div><div>        if opts.verbose == &#39;help&#39;:</div><div>            print MythLog.helptext</div>
<div>            sys.exit(0)</div><div>        MythLog._setlevel(opts.verbose)</div><div><br></div><div>    if len(args) == 1:</div><div>        runjob(jobid=args[0])</div><div>    elif opts.chanid and opts.starttime:</div>
<div>        runjob(chanid=opts.chanid, starttime=opts.starttime)</div><div>    else:</div><div>        print &#39;Script must be provided jobid, or chanid and starttime.&#39;</div><div>        sys.exit(1)</div><div><br></div>
<div>if __name__ == &#39;__main__&#39;:</div><div>    main()</div><div> </div></div><br>