OK with some hacking I got the 16:9 detection to work reliably. On my current set of testfiles it works a treat.
So I am now sharing the file (to go into video/plugins) for others to play with.

So please provide feedback if you find a case where it does not work as expected.

Paul


On 26-01-10 12:02, John Molohan wrote:
Interesting, thanks for the update.

John

On 25/01/2010 6:11, Paul Sijben wrote:
OK found it. The problem was that the detetection performed did not play well with the not-so-black bars in the recording. However giving a limit value to cropdetect does not always yield the desired result. So I am preparing a patch for video/plugins/mplayer.py that will yield the correct result.

 

On 24-01-10 11:52, Paul Sijben wrote:
I am in the process of converting my freevo setup to new hardware and a new 16:9 screen (1360x768)

I tried to set it up correctly but apparently I have forgotten something as recorded wide screen broadcasts now have black bars all around. So I turned on debugging and found this in the mplayer log:

CommandLine: '-slave' '-v' '-vo' 'xv,sdl,x11,' '-ao' 'oss:/dev/dsp' '-autosync' '100' '-nolirc' '-nojoystick' '-autoq' '100' '-screenw' '1360' '-screenh' '768' '-fs' '-cache' '5000' '-monitoraspect' '16:9' '-af' 'volnorm=1' '-vf' 'pp=de,crop=720:576:0:0' '//home/freevo/tvrecordings/12-26_1430_Bridge_to_Terabithia.mpeg'

so it is told of the screen size and aspect but then does not crop the video to the correct part.

What should I do to have recorded TV cropped correctly?

Paul

-- 
Paul Sijben
tel 0334557522
  
------------------------------------------------------------------------------ Throughout its 18-year history, RSA Conference consistently attracts the world's best and brightest in the field, creating opportunities for Conference attendees to learn about information security's most important issues through interactions with peers, luminaries and emerging and established companies. http://p.sf.net/sfu/rsaconf-dev2dev
_______________________________________________ Freevo-users mailing list Freevo-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/freevo-users

-- 
Paul Sijben
tel 0334557522
  
------------------------------------------------------------------------------ Throughout its 18-year history, RSA Conference consistently attracts the world's best and brightest in the field, creating opportunities for Conference attendees to learn about information security's most important issues through interactions with peers, luminaries and emerging and established companies. http://p.sf.net/sfu/rsaconf-dev2dev
_______________________________________________ Freevo-users mailing list Freevo-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/freevo-users


-- 
John Molohan
IT Manager

Griffith College Dublin
South Circular Road
Dublin 8
Ireland

Phone: +353 1 4163366
Web: www.it.gcd.ie www.gcd.ie

Disclaimer:
This E-mail is from Griffith College Dublin.
The E-mail and any files transmitted with it are confidential and may be privileged and are intended solely for the use of the individual or entity to whom they are addressed. If you are not the addressee you are prohibited from disclosing its content, copying it or distributing it otherwise than to the addressee. If you have received this e-mail in error, please immediately notify the sender by replying to this e-mail and delete the e-mail from your computer.

Bellerophon Ltd, trades as Griffith College (registered in Ireland No. 60469) with its registered address as Griffith College Campus, South Circular Road, Dublin 8, Ireland.
  
------------------------------------------------------------------------------ The Planet: dedicated and managed hosting, cloud storage, colocation Stay online with enterprise data centers and the best network in the business Choose flexible plans and management services without long-term contracts Personal 24x7 support from experience hosting pros just a phone call away. http://p.sf.net/sfu/theplanet-com
_______________________________________________ Freevo-users mailing list Freevo-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/freevo-users

-- 
Paul Sijben
tel 0334557522
# -*- coding: iso-8859-1 -*-
# -----------------------------------------------------------------------
# Freevo video module for MPlayer
# -----------------------------------------------------------------------
# $Id: mplayer.py 11479 2009-05-07 17:34:38Z duncan $
# -----------------------------------------------------------------------
# Freevo - A Home Theater PC framework
# Copyright (C) 2002 Krister Lagerstrom, et al.
# Please see the file freevo/Docs/CREDITS for a complete list of authors.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# -----------------------------------------------------------------------

"""
Freevo video module for MPlayer
"""

import os, re
import threading
import popen2
import kaa.metadata as mmpython

import config     # Configuration handler. reads config file.
import util       # Various utilities
import childapp   # Handle child applications
import rc         # The RemoteControl class.
import plugin
import dialog
from dialog.display import AppTextDisplay

from event import *


class PluginInterface(plugin.Plugin):
    """
    Mplayer plugin for the video player.

    With this plugin Freevo can play all video files defined in
    VIDEO_MPLAYER_SUFFIX. This is the default video player for Freevo.
    """
    def __init__(self):
        # create plugin structure
        plugin.Plugin.__init__(self)
        # register mplayer as the object to play video
        plugin.register(MPlayer(), plugin.VIDEO_PLAYER, True)



class MPlayer:
    """
    the main class to control mplayer
    """
    def __init__(self):
        """
        init the mplayer object
        """
        self.name       = 'mplayer'

        self.app_mode   = 'video'
        self.seek       = 0
        self.seek_timer = threading.Timer(0, self.reset_seek)
        self.app        = None
        self.plugins    = []
        self.paused     = False
        self.stored_time_info = None
        self.audio_media = None
        self.subtitle_media = None


    def rate(self, item):
        """
        How good can this player play the file:
        2 = good
        1 = possible, but not good
        0 = unplayable
        """
        if not item.url:
            return 0
        # this seems strange that it is 'possible' for dvd:// and 'good' for dvd
        # possible because dvd:// should be played with xine when available!
        if item.url[:6] in ('dvd://', 'vcd://') and item.url.endswith('/'):
            _debug_('mplayer rating: %r possible' % (item.url), 2)
            return 1
        if item.mode in ('dvd', 'vcd'):
            _debug_('mplayer rating: %r good' % (item.url), 2)
            return 2
        if item.mode in ('http') and not item.filename and not item.media:
            _debug_('mplayer rating: %r good' % (item.url), 2)
            return 2
        if item.mimetype in config.VIDEO_MPLAYER_SUFFIX:
            _debug_('mplayer rating: %r good' % (item.url), 2)
            return 2
        if item.network_play:
            _debug_('mplayer rating: %r possible' % (item.url), 2)
            return 1
        _debug_('mplayer rating: %r unplayable' % (item.url), 2)
        return 0


    def play(self, options, item):
        """
        play a videoitem with mplayer
        """
        _debug_('options=%r' % (options,), 2)
        for k, v in item.__dict__.items():
            _debug_('item[%s]=%r' % (k, v), 2)

        mode         = item.mode
        url          = item.url

        self.options = options
        self.item    = item
        self.item_info    = None
        self.item_length  = -1
        self.item.elapsed = 0

        if mode == 'file':
            url = item.url[6:]
            self.item_info = mmpython.parse(url)
            if hasattr(self.item_info, 'get_length'):
                self.item_length = self.item_info.get_endpos()
                self.dynamic_seek_control = True

        if url.startswith('dvd://') and url[-1] == '/':
            url += '1'

        if url == 'vcd://':
            c_len = 0
            for i in range(len(item.info.tracks)):
                if item.info.tracks[i].length > c_len:
                    c_len = item.info.tracks[i].length
                    url = item.url + str(i+1)

        url=Unicode(url)
        try:
            _debug_('MPlayer.play(): mode=%s, url=%s' % (mode, url))
        except UnicodeError:
            _debug_('MPlayer.play(): [non-ASCII data]')

        if mode == 'file' and not os.path.isfile(url):
            # This event allows the videoitem which contains subitems to
            # try to play the next subitem
            return '%s\nnot found' % os.path.basename(url)

        set_vcodec = False
        if item['xvmc'] and item['type'][:6] in ['MPEG-1', 'MPEG-2', 'MPEG-T']:
            set_vcodec = True

        mode = item.mimetype
        if not config.MPLAYER_ARGS.has_key(mode):
            _debug_('MPLAYER_ARGS not defined for %r, using default' % mode, 
DINFO)
            mode = 'default'

        _debug_('mode=%s args=%s'% (mode, config.MPLAYER_ARGS[mode]))
        # Build the MPlayer command
        args = {
            'nice': config.MPLAYER_NICE,
            'cmd': config.MPLAYER_CMD,
            'vo': '-vo %s' % config.MPLAYER_VO_DEV,
            'vo_opts': config.MPLAYER_VO_DEV_OPTS,
            'vc': '',
            'ao': '-ao %s' % config.MPLAYER_AO_DEV,
            'ao_opts': config.MPLAYER_AO_DEV_OPTS,
            'default_args': config.MPLAYER_ARGS_DEF,
            'mode_args': config.MPLAYER_ARGS[mode],
            'fxd_args': ' '.join(options),
            'geometry': '',
            'verbose': '',
            'dvd-device': '',
            'cdrom-device': '',
            'alang': '',
            'aid': '',
            'slang': '',
            'sid': '',
            'playlist': '',
            'field-dominance': '',
            'edl': '',
            'mc': '',
            'delay': '',
            'sub': '',
            'audiofile': '',
            'af': [],
            'vf': [],
            'url': url,
            'disable_osd': False,
        }

        if config.CONF.x or config.CONF.y:
            args['geometry'] = '-geometry %d:%d' % (config.CONF.x, 
config.CONF.y)

        if config.DEBUG_CHILDAPP:
            args['verbose'] = '-v'

        if mode == 'dvd':
            if config.DVD_LANG_PREF:
                # There are some bad mastered DVDs out there. E.g. the specials 
on
                # the German Babylon 5 Season 2 disc claim they have more than 
one
                # audio track, even more then on en. But only the second en 
works,
                # mplayer needs to be started without -alang to find the track
                if hasattr(item, 'mplayer_audio_broken') and 
item.mplayer_audio_broken:
                    print '*** dvd audio broken, try without alang ***'
                else:
                    args['alang'] = '-alang %s' % config.DVD_LANG_PREF

            if config.DVD_SUBTITLE_PREF:
                # Only use if defined since it will always turn on subtitles 
when defined
                args['slang'] = '-slang %s' % config.DVD_SUBTITLE_PREF

        if mode == 'dvd':
            # dvd on harddisc
            args['dvd-device'] = '%s' % item.filename
            args['url'] = url[:6] + url[url.rfind('/')+1:]
        elif mode != 'file' and hasattr(item.media, 'devicename'):
            args['dvd-device'] = '%s' % item.media.devicename

        if item.media and hasattr(item.media, 'devicename'):
            args['cdrom-device'] = '%s' % item.media.devicename

        if item.selected_subtitle == -1:
            args['sid'] = '-noautosub'
        elif item.selected_subtitle is not None:
            if mode == 'file':
                if os.path.isfile(os.path.splitext(item.filename)[0]+'.idx'):
                    args['sid'] = '-vobsubid %s' % str(item.selected_subtitle)
                else:
                    args['sid'] = '-sid %s' % str(item.selected_subtitle)
            else:
                args['sid'] = '-sid %s' % str(item.selected_subtitle)

        if item.selected_audio is not None:
            args['aid'] = '-aid %s' % str(item.selected_audio)

        # This comes from the bilingual language selection menu
        if hasattr(item, 'selected_language') and item.selected_language:
            if item.selected_language == 'left':
                args['af'].append('pan=2:1:1:0:0')
            elif item.selected_language == 'right':
                args['af'].append('pan=2:0:0:1:1')

        if not set_vcodec:
            if item['deinterlace'] and config.MPLAYER_VF_INTERLACED:
                args['vf'].append(config.MPLAYER_VF_INTERLACED)
            elif config.MPLAYER_VF_PROGRESSIVE:
                args['vf'].append(config.MPLAYER_VF_PROGRESSIVE)

        if config.VIDEO_FIELD_DOMINANCE is not None:
            args['field-dominance'] = '-field-dominance %d' % 
int(item['field-dominance'])

        if os.path.isfile(os.path.splitext(item.filename)[0]+'.edl'):
            args['edl'] = '-edl %s' % 
str(os.path.splitext(item.filename)[0]+'.edl')

        if dialog.overlay_display_supports_dialogs:
            # Disable the mplayer OSD if we have a better option.
            args['disable_osd'] = True

        # Mplayer command and standard arguments
        if set_vcodec:
            if item['deinterlace']:
                bobdeint='bobdeint'
            else:
                bobdeint='nobobdeint'
            args['vo'] = '-vo xvmc:%s' % bobdeint
            args['vc'] = '-vc ffmpeg12mc'

        if hasattr(item, 'is_playlist') and item.is_playlist:
            args['playlist'] = '-playlist'

        # correct avi delay based on kaa.metadata settings
        if config.MPLAYER_SET_AUDIO_DELAY and item.info.has_key('delay') and 
item.info['delay'] > 0:
            args['mc'] = '-mc %s' % str(int(item.info['delay'])+1)
            args['delay'] = '-delay -%s' % str(item.info['delay'])

        # autocrop
        if config.MPLAYER_AUTOCROP and not item.network_play and 
args['fxd_args'].find('crop=') == -1:
            _debug_('starting autocrop points=%s'%config.MPLAYER_AUTOCROP_START)
            (x1, y1, x2, y2) = (1000, 1000, 0, 0)
            #new approach; detect if this is 16:9 or 4:3
            crop_point=config.TV_RECORD_PADDING_PRE+60
            (x1, y1, x2, y2) = self.get_crop(crop_point, x1, y1, x2, y2)
            _debug_('set=%s'%(str((x1, y1, x2, y2))))
            if y1==0 and float(x2-x1)/max(float(y2-y1),1)<1.5:
                #ah 4:3, let's investigate further
                #now we have the max size (720x576 for tv recordings)
                #however the upper and lower bars of a TV recording are not 
black enough
                count_16by9 = 0
                count_4by3 = 0
                for ii in range(0,4):
                    if ii:
                        crop_point+=3*60
                    #jump through the movie with 3 min intervals
                    (x11, y11, x21, y21) = (1000, 1000, 0, 0)
                    isit,x11,y11,x21,y21= 
self.is16by9(crop_point,x11,y11,x21,y21)
                    if isit:
                        count_16by9+=1
                    else:
                        count_4by3+=1
                if count_16by9>count_4by3:
                        #ah adapt the crop params
                        height=y2-y1
                        w=x2-x1
                        if w==720: w=768
                        factor = float(config.CONF.width)/float(w)
                        cropheight = int(.5+(config.CONF.height/factor))
                        _debug_('height=%s w=%s factor=%s 
cropheight=%s'%(height,w,factor,cropheight))
                        #OK cut top and bottom in equal amounts
                        y1=int((height-cropheight)/2)
                        y2=y1+cropheight
                        _debug_('y1=%s y2=%s'%(y1,y2))

            if x1 < 1000 and x2 < 1000:
                args['vf'].append('crop=%s:%s:%s:%s' % (x2-x1, y2-y1, x1, y1))
                _debug_('crop=%s:%s:%s:%s' % (x2-x1, y2-y1, x1, y1))

        if item.subtitle_file:
            self.subtitle_media, f = 
util.resolve_media_mountdir(item.subtitle_file)
            if self.subtitle_media:
                self.subtitle_media.mount()
            args['sub'] = '-sub %s' % f

        if item.audio_file:
            self.audio_media, f = util.resolve_media_mountdir(item.audio_file)
            if self.audio_media:
                self.audio_media.mount()
            args['audiofile'] = '-audiofile %s' % f

        self.plugins = plugin.get('mplayer_video')
        for p in self.plugins:
            command = p.play(command, self)

        vo = ['%(vo)s' % args, '%(vo_opts)s' % args]
        vo = filter(len, vo)
        vo = ':'.join(vo)

        ao = ['%(ao)s' % args, '%(ao_opts)s' % args]
        ao = filter(len, ao)
        ao = ':'.join(ao)

        # process the mplayer options extracting video and audio filters
        args['default_args'], args = self.find_filters(args['default_args'], 
args)
        args['mode_args'], args = self.find_filters(args['mode_args'], args)
        args['fxd_args'], args = self.find_filters(args['fxd_args'], args)

        command = ['--prio=%(nice)s' % args]
        command += ['%(cmd)s' % args]
        command += ['-slave']
        command += str('%(verbose)s' % args).split()
        command += str('%(geometry)s' % args).split()
        command += vo.split()
        command += str('%(vc)s' % args).split()
        command += ao.split()
        command += args['dvd-device'] and ['-dvd-device', '%(dvd-device)s' % 
args] or []
        command += args['cdrom-device'] and ['-cdrom-device', 
'%(cdrom-device)s' % args] or []
        command += str('%(alang)s' % args).split()
        command += str('%(aid)s' % args).split()
        command += str('%(audiofile)s' % args).split()
        command += str('%(slang)s' % args).split()
        command += str('%(sid)s' % args).split()
        command += str('%(sub)s' % args).split()
        command += str('%(field-dominance)s' % args).split()
        command += str('%(edl)s' % args).split()
        command += str('%(mc)s' % args).split()
        command += str('%(delay)s' % args).split()
        command += args['default_args'].split()
        command += args['mode_args'].split()
        command += args['fxd_args'].split()
        command += args['af'] and ['-af', '%s' % ','.join(args['af'])] or []
        command += args['vf'] and ['-vf', '%s' % ','.join(args['vf'])] or []
        command += args['disable_osd'] and ['-osdlevel', '0'] or []

        # use software scaler?
        #XXX these need to be in the arg list as the scaler will add vf args
        if '-nosws' in command:
            command.remove('-nosws')
        elif '-framedrop' not in command:
            command += config.MPLAYER_SOFTWARE_SCALER.split()

        command = filter(len, command)

        command += str('%(playlist)s' % args).split()
        command += ['%(url)s' % args]

        _debug_(' '.join(command[1:]))

        #if plugin.getbyname('MIXER'):
            #plugin.getbyname('MIXER').reset()

        self.paused = False

        rc.app(self)
        self.app = MPlayerApp(command, self)
        dialog.enable_overlay_display(AppTextDisplay(self.show_message))
        return None


    def stop(self):
        """
        Stop mplayer
        """
        for p in self.plugins:
            command = p.stop()

        if not self.app:
            return

        self.app.stop('quit\n')
        rc.app(None)
        dialog.disable_overlay_display()
        self.app = None

        if self.subtitle_media:
            self.subtitle_media.mount()
            self.subtitle_media = None

        if self.audio_media:
            self.audio_media.mount()
            self.audio_media = None


    def eventhandler(self, event, menuw=None):
        """
        eventhandler for mplayer control. If an event is not bound in this
        function it will be passed over to the items eventhandler
        """
        if not self.app:
            return self.item.eventhandler(event)

        for p in self.plugins:
            if p.eventhandler(event):
                return True

        if event == VIDEO_MANUAL_SEEK:
            self.seek = 0
            rc.set_context('input')
            dialog.show_message("input")
            return True

        if event.context == 'input':
            if event in INPUT_ALL_NUMBERS:
                self.reset_seek_timeout()
                self.seek = self.seek * 10 + int(event);
                return True

            elif event == INPUT_ENTER:
                self.seek_timer.cancel()
                self.seek *= 60
                self.app.write('seek ' + str(self.seek) + ' 2\n')
                _debug_("seek "+str(self.seek)+" 2\n")
                self.seek = 0
                rc.set_context('video')
                return True

            elif event == INPUT_EXIT:
                _debug_('seek stopped')
                #self.app.write('seek stopped\n')
                self.seek_timer.cancel()
                self.seek = 0
                rc.set_context('video')
                return True

        if event == STOP:
            self.stop()
            return self.item.eventhandler(event)

        if event == 'AUDIO_ERROR_START_AGAIN':
            self.stop()
            self.play(self.options, self.item)
            return True

        if event in (PLAY_END, USER_END):
            self.stop()
            return self.item.eventhandler(event)

        if event == VIDEO_SEND_MPLAYER_CMD:
            self.app.write('%s\n' % event.arg)
            return True

        if event == TOGGLE_OSD:
            if dialog.is_dialog_supported():
                if self.paused:
                    dialog.show_play_state(dialog.PLAY_STATE_PAUSE , 
self.get_stored_time_info)
                else:
                    dialog.show_play_state(dialog.PLAY_STATE_PLAY, 
self.get_time_info)
            else:
                self.app.write('osd\n')
            return True

        if event == PAUSE or event == PLAY:
            self.paused = not self.paused
            # We have to store the current time before displaying the dialog
            # otherwise the act of requesting the current position resumes 
playback!
            if self.paused:
                self.stored_time_info = self.get_time_info()
                dialog.show_play_state(dialog.PLAY_STATE_PAUSE, 
self.get_time_info)
                self.app.write('pause\n')
            else:
                self.app.write('pause\n')
                dialog.show_play_state(dialog.PLAY_STATE_PLAY, 
self.get_time_info)

            return True

        if event == SEEK:
            if event.arg > 0 and self.item_length != -1 and 
self.dynamic_seek_control:
                # check if the file is growing
                if self.item_info.get_endpos() == self.item_length:
                    # not growing, deactivate this
                    self.item_length = -1

                self.dynamic_seek_control = False

            if event.arg > 0 and self.item_length != -1:
                # safety time for bad mplayer seeking
                seek_safety_time = 20
                if self.item_info['type'] in ('MPEG-PES', 'MPEG-TS'):
                    seek_safety_time = 500

                # check if seek is allowed
                if self.item_length <= self.item.elapsed + event.arg + 
seek_safety_time:
                    # get new length
                    self.item_length = self.item_info.get_endpos()

                # check again if seek is allowed
                if self.item_length <= self.item.elapsed + event.arg + 
seek_safety_time:
                    _debug_('unable to seek %s secs at time %s, length %s' % \
                            (event.arg, self.item.elapsed, self.item_length))

                    dialog.show_message(_('Seeking not possible'))
                    return False

            if event.arg > 0:
                dialog.show_play_state(dialog.PLAY_STATE_SEEK_FORWARD, 
self.get_time_info)
            else:
                dialog.show_play_state(dialog.PLAY_STATE_SEEK_BACK, 
self.get_time_info)

            self.app.write('seek %s\n' % event.arg)
            return True

        if event == VIDEO_AVSYNC:
            self.app.write('audio_delay %g\n' % event.arg);
            return True

        if event == VIDEO_NEXT_AUDIOLANG:
            self.app.write('switch_audio\n')
            return True

        if event == VIDEO_NEXT_SUBTITLE:
            self.app.write('sub_select\n')
            return True

        if event == OSD_MESSAGE:
            self.show_message(event.arg)
            return True

        # nothing found? Try the eventhandler of the object who called us
        return self.item.eventhandler(event)

    def show_message(self, message):
        self.app.write('osd_show_text "%s"\n' % message);

    def reset_seek(self):
        _debug_('seek timeout')
        self.seek = 0
        rc.set_context('video')


    def reset_seek_timeout(self):
        self.seek_timer.cancel()
        self.seek_timer = threading.Timer(config.MPLAYER_SEEK_TIMEOUT, 
self.reset_seek)
        self.seek_timer.start()


    def find_filters(self, arg, args):
        old_options = arg.split('-')
        new_options = []
        for i in range(len(old_options)):
            pair = old_options[i].split()
            if len(pair) == 2:
                if pair[0] == 'vf':
                    args['vf'].append(pair[1])
                    continue
                elif pair[0] == 'af':
                    args['af'].append(pair[1])
                    continue
            new_options.append(old_options[i])
        arg = '-'.join(new_options)
        return arg, args


    def sort_filter(self, command):
        """
        Change a mplayer command to support more than one -vf parameter. This
        function will grep all -vf parameter from the command and add it at the
        end as one vf argument
        """
        ret = []
        vf = ''
        next_is_vf = False

        for arg in command:
            if next_is_vf:
                vf += ',%s' % arg
                next_is_vf = False
            elif (arg == '-vf'):
                next_is_vf=True
            else:
                ret += [arg]

        if vf:
            return ret + ['-vf', vf[1:]]
        return ret


    def get_crop(self, pos, x1, y1, x2, y2, threshold=None):
        if threshold:
            crop_cmd = [config.MPLAYER_CMD, '-ao', 'null', '-vo', 'null', 
'-slave', '-nolirc',
                        '-ss', '%s' % pos, '-frames', '6', '-vf', 
'cropdetect=%s'%threshold]
        else:
            crop_cmd = [config.MPLAYER_CMD, '-ao', 'null', '-vo', 'null', 
'-slave', '-nolirc',
                        '-ss', '%s' % pos, '-frames', '6', '-vf', 'cropdetect']
        crop_cmd.append(self.item.url)
        child = popen2.Popen3(self.sort_filter(crop_cmd), 1, 100)
        exp = re.compile('^.*-vf crop=([0-9]*):([0-9]*):([0-9]*):([0-9]*).*')
        gotone=False
        while(1):
            data = child.fromchild.readline()
            if not data:
                if not gotone:
                   return self.get_crop(0,x1,y1,x2,y2,threshold)
                break
            m = exp.match(data)
            if m:
                x1 = min(x1, int(m.group(3)))
                y1 = min(y1, int(m.group(4)))
                x2 = max(x2, int(m.group(1)) + int(m.group(3)))
                y2 = max(y2, int(m.group(2)) + int(m.group(4)))
                _debug_('x1=%s x2=%s y1=%s y2=%s' % (x1, x2, y1, y2))
                gotone=True
        child.wait()
        return (x1, y1, x2, y2)

    def is16by9(self,crop_point,x1,y1,x2,y2,threshold=54):
        _debug_('croppoint=%s thresh=%s ' % (crop_point,threshold))

        (x12, y12, x22, y22) = self.get_crop(crop_point, x1,y1,x2,y2,threshold)
        if y22==0: y22=1
        _debug_('x1=%s x2=%s y1=%s y2=%s x2/y2=%s' % (x12, x22, y12, 
y22,float(x22)/float(y22)))
        return float(x22)/float(y22)>1.27,x12,y12,x22,y22


    def get_stored_time_info(self):
        return self.stored_time_info

    def get_time_info(self):
        time_pos = self.app.get_property('time_pos')
        length = self.app.get_property('length')
        percent_pos = self.app.get_property('percent_pos')
        return (int(float(time_pos)), int(float(length)), int(percent_pos) / 
100.0)


# ======================================================================


class MPlayerApp(childapp.ChildApp2):
    """
    class controlling the in and output from the mplayer process
    """

    def __init__(self, command, mplayer):
        self.RE_TIME   = re.compile("^[AV]: *([0-9]+)").match
        self.RE_START  = re.compile("^Starting playback\.\.\.").match
        self.RE_EXIT   = re.compile("^Exiting\.\.\. \((.*)\)$").match
        self.item      = mplayer.item
        self.mplayer   = mplayer
        self.exit_type = None

        # DVD items also store mplayer_audio_broken to check if you can
        # start them with -alang or not
        if hasattr(self.item, 'mplayer_audio_broken') or self.item.mode != 
'dvd':
            self.check_audio = 0
        else:
            self.check_audio = 1

        import osd
        self.osd     = osd.get_singleton()
        self.osdfont = self.osd.getfont(config.OSD_DEFAULT_FONTNAME, 
config.OSD_DEFAULT_FONTSIZE)

        # check for mplayer plugins
        self.stdout_plugins  = []
        self.elapsed_plugins = []
        for p in plugin.get('mplayer_video'):
            if hasattr(p, 'stdout'):
                self.stdout_plugins.append(p)
            if hasattr(p, 'elapsed'):
                self.elapsed_plugins.append(p)

        self.output_event = threading.Event()
        self.get_property_ans = None
        # init the child (== start the threads)
        childapp.ChildApp2.__init__(self, command, callback_use_rc=False)

    def get_property(self, property):
        self.get_property_ans = None
        self.output_event.clear()
        self.write('get_property %s\n' % property)
        self.output_event.wait()
        return self.get_property_ans

    def stop_event(self):
        """
        return the stop event send through the eventhandler
        """
        if self.exit_type == "End of file":
            return PLAY_END
        elif self.exit_type == "Quit":
            return USER_END
        else:
            return PLAY_END


    def stdout_cb(self, line):
        """
        parse the stdout of the mplayer process
        """
        # show connection status for network play
        if self.item.network_play:
            if line.find('Opening audio decoder') == 0:
                self.osd.clearscreen(self.osd.COL_BLACK)
                self.osd.update()
            elif (line.startswith('Resolving ') or \
                  line.startswith('Connecting to server') or \
                  line.startswith('Cache fill:')) and \
                  line.find('Resolving reference to') == -1:

                if line.startswith('Connecting to server'):
                    line = 'Connecting to server'
                self.osd.clearscreen(self.osd.COL_BLACK)
                self.osd.drawstringframed(line, config.OSD_OVERSCAN_LEFT+10, 
config.OSD_OVERSCAN_TOP+10,
                    self.osd.width - (config.OSD_OVERSCAN_LEFT+10 + 
config.OSD_OVERSCAN_RIGHT+10),
                    -1, self.osdfont, self.osd.COL_WHITE)
                self.osd.update()


        # current elapsed time
        if line.startswith("A:") or line.startswith("V:"):
            m = self.RE_TIME(line)
            if hasattr(m, 'group') and self.item.elapsed != int(m.group(1))+1:
                self.item.elapsed = int(m.group(1))+1
                for p in self.elapsed_plugins:
                    p.elapsed(self.item.elapsed)


        # exit status
        elif line.find("Exiting...") == 0:
            m = self.RE_EXIT(line)
            if m:
                self.exit_type = m.group(1)
            if self.output_event.isSet():
                self.output_event.set()

        elif line.startswith('ANS_'):
            prop,ans = line.split('=')
            self.get_property_ans = ans.strip()
            self.output_event.set()

        # this is the first start of the movie, parse info
        elif not self.item.elapsed:
            for p in self.stdout_plugins:
                p.stdout(line)

            if self.check_audio:
                if line.find('MPEG: No audio stream found -> no sound') == 0:
                    # OK, audio is broken, restart without -alang
                    self.check_audio = 2
                    self.item.mplayer_audio_broken = True
                    rc.post_event(Event('AUDIO_ERROR_START_AGAIN'))

                if self.RE_START(line):
                    if self.check_audio == 1:
                        # audio seems to be ok
                        self.item.mplayer_audio_broken = False
                    self.check_audio = 0



    def stderr_cb(self, line):
        """
        parse the stderr of the mplayer process
        """
        if line.startswith('Failed to get value of property '):
            self.output_event.set()

        for p in self.stdout_plugins:
            p.stdout(line)
------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation
Stay online with enterprise data centers and the best network in the business
Choose flexible plans and management services without long-term contracts
Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com
_______________________________________________
Freevo-users mailing list
Freevo-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/freevo-users

Reply via email to