Index: mythplugins/mythweb/themes/wml/header.php =================================================================== --- mythplugins/mythweb/themes/wml/header.php (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweb/themes/wml/header.php (.../branches/release-0-19-fixes) (revision 10931) @@ -26,4 +26,4 @@

-

+

Index: mythplugins/mythweb/themes/default/weather/weather.php =================================================================== --- mythplugins/mythweb/themes/default/weather/weather.php (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweb/themes/default/weather/weather.php (.../branches/release-0-19-fixes) (revision 10931) @@ -93,13 +93,13 @@ $tomorrow = date("m/d/Y", mktime(0, 0, 0, date("m") , date("d")+1, date("Y"))); switch($forecast->dayofweek) { + case 0: $day = t('Sunday'); break; case 1: $day = t('Monday'); break; case 2: $day = t('Tuesday'); break; case 3: $day = t('Wednesday'); break; case 4: $day = t('Thursday'); break; case 5: $day = t('Friday'); break; case 6: $day = t('Saturday'); break; - case 7: $day = t('Sunday'); break; default: $day = $forecast->date; break; } Index: mythplugins/mythweb/themes/default/music/music.php =================================================================== --- mythplugins/mythweb/themes/default/music/music.php (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweb/themes/default/music/music.php (.../branches/release-0-19-fixes) (revision 10931) @@ -164,10 +164,12 @@ function print_header($filterPlaylist,$filterArtist,$filterAlbum,$filterGenre) { $this->filterPlaylist=$filterPlaylist; -// Set the desired page title - $page_title = 'MythWeb - '.t('Music'); -// Print the page header - require_once theme_dir.'/header.php'; + // Set the desired page title + global $page_title, $Modules, $headers; + $page_title = 'MythWeb - '.t('Music'); + // Print the page header + require_once theme_dir.'/header.php'; + printf("
\n"); printf("\n"); Index: mythplugins/mythweb/themes/default/tv/detail.php =================================================================== --- mythplugins/mythweb/themes/default/tv/detail.php (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweb/themes/default/tv/detail.php (.../branches/release-0-19-fixes) (revision 10931) @@ -51,7 +51,7 @@

- title ?> + title ?>

chanid] = &$Channels[$key]; + $channel_hash[$Channels[$key]->chanid] =& $Channels[$key]; // Reinitialize the programs array for this channel $Channels[$key]->programs = array(); // Keep track of this channel id in case we're only grabbing info for certain channels - workound included to avoid blank chanid's @@ -130,11 +132,13 @@ LEFT JOIN programrating USING (chanid, starttime) LEFT JOIN oldrecorded ON oldrecorded.recstatus IN (-3, 11) - AND IF(oldrecorded.programid OR oldrecorded.seriesid, + AND IF(oldrecorded.programid AND oldrecorded.seriesid, oldrecorded.programid = program.programid AND oldrecorded.seriesid = program.seriesid, - oldrecorded.title = program.title - AND oldrecorded.subtitle = program.subtitle + oldrecorded.title AND oldrecorded.subtitle + AND oldrecorded.description + AND oldrecorded.title = program.title + AND oldrecorded.subtitle = program.subtitle AND oldrecorded.description = program.description ) LEFT JOIN channel ON program.chanid = channel.chanid @@ -156,8 +160,12 @@ // The extra query, if there is one if ($extra_query) $query .= ' AND '.$extra_query; - // Group, sort and query + // Group and sort $query .= ' GROUP BY program.chanid, program.starttime ORDER BY program.starttime'; + // Limit + if ($single_program) + $query .= ' LIMIT 1'; + // Query $sh = $db->query($query, star_character, max_stars, max_stars); // No results @@ -188,12 +196,8 @@ // Cleanup $sh->finish(); // If channel-specific information was requested, return an array of those programs, or just the first/only one - if ($chanid) { - if ($single_program) - return $channel_hash[$chanid]->programs[0]; - else - return $channel_hash[$chanid]->programs; - } + if ($chanid && $single_program) + return $these_programs[0]; // Just in case, return an array of all programs found return $these_programs; } @@ -272,18 +276,18 @@ $this->endtime = $data[12]; # show end-time // Is this a previously-recorded program? Calculate the filesize if (!empty($this->filename)) { - $this->filesize = ($fs_high + ($fs_low < 0)) * 4294967296 + $fs_low; - } - // Ah, a scheduled recording - let's load more information about it, to be parsed in below - elseif ($this->chanid) { - unset($this->filename); - // Kludge to avoid redefining the object, which doesn't work in php5 - $tmp = @get_object_vars(load_one_program($this->starttime, $this->chanid)); - if (is_array($tmp) && count($tmp) > 0) { - foreach ($tmp as $key => $value) { - $this->$key = $value; - } + if (function_exists('gmp_add')) { + // GMP functions should work better with 64 bit numbers. + $size = gmp_add($fs_low, + gmp_mul('4294967296', + gmp_add($fs_high, $fs_low < 0 ? '1' : '0')) + ); + $this->filesize = gmp_strval($size); } + else { + // This is inaccurate, but it's the best we can get without GMP. + $this->filesize = ($fs_high + ($fs_low < 0)) * 4294967296 + $fs_low; + } } // Load the remaining info we got from mythbackend $this->title = $data[0]; # program name/title @@ -291,14 +295,14 @@ $this->description = $data[2]; # episode description $this->category = $data[3]; #$chanid = $data[4]; # Extracted a few lines earlier - #$channum = $data[5]; - #$callsign = $data[6]; + $this->channum = $data[5]; + $this->callsign = $data[6]; $this->channame = $data[7]; #$pathname = $data[8]; # Extracted a few lines earlier #$fs_high = $data[9]; # Extracted a few lines earlier #$fs_low = $data[10]; # Extracted a few lines earlier - #$starttime = $data[11]; # Extracted a few lines earlier - #$endtime = $data[12]; # Extracted a few lines earlier + #$this->starttime = $data[11]; # Extracted a few lines earlier + #$this->endtime = $data[12]; # Extracted a few lines earlier $this->hostname = $data[16]; #$this->sourceid = $data[17]; $this->cardid = $data[18]; @@ -320,9 +324,9 @@ $this->programid = $data[34]; $this->lastmodified = $data[35]; $this->recpriority = $data[36]; - #$this->airdate = $data[37]; - #$this->hasairdate = $data[38]; - $this->timestretch = $program_data[39]; + $this->airdate = date('Y-m-d', $data[37]); + $this->hasairdate = $data[38]; + $this->timestretch = $data[39]; $this->recpriority2 = $data[40]; // Assign the program flags $this->has_commflag = ($progflags & 0x01) ? true : false; // FL_COMMFLAG = 0x01 @@ -363,8 +367,8 @@ $this->title_pronounce = $data['title_pronounce']; $this->recstatus = $data['recstatus']; - if ($program_data['tsdefault']) { - $this->timestretch = $program_data['tsdefault']; + if ($data['tsdefault']) { + $this->timestretch = $data['tsdefault']; } else { $this->timestretch = 1.0; } @@ -387,12 +391,14 @@ // Now we really should scan the $Channel array and add a link to this program's channel foreach (array_keys($Channels) as $key) { if ($Channels[$key]->chanid == $this->chanid) { - $this->channel = &$Channels[$key]; + $this->channel =& $Channels[$key]; break; } } + // Not found + if (!$this->channel) + $this->channel =& load_one_channel($this->chanid); } - // Calculate the duration if ($this->recendts) $this->length = $this->recendts - $this->recstartts; Index: mythplugins/mythweb/includes/utils.php =================================================================== --- mythplugins/mythweb/includes/utils.php (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweb/includes/utils.php (.../branches/release-0-19-fixes) (revision 10931) @@ -276,7 +276,7 @@ static $first_run=true; if($first_run) { $first_run=false; - echo ''; + echo ''; } // Put our data into a string if (is_array($data) || is_object($data)) Index: mythplugins/mythweb/includes/init.php =================================================================== --- mythplugins/mythweb/includes/init.php (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweb/includes/init.php (.../branches/release-0-19-fixes) (revision 10931) @@ -16,28 +16,15 @@ * /**/ -/** - * $Path is an array of PATH_INFO passed into the script via mod_rewrite or some - * other lesser means. It contains most of the information required for - * figuring out what functions the user wants to access. - * - * @global array $GLOBALS['Path'] - * @name $Path -/**/ - global $Path; - $Path = explode('/', preg_replace('/^\/+/', '', // Remove leading slashes - preg_replace('/[\s]+/', ' ', // Convert extra whitespace - // Grab the path info from various different places. - array_key_exists('PATH_INFO', $_SERVER) - && $_SERVER['PATH_INFO'] - ? $_SERVER['PATH_INFO'] - : (array_key_exists('PATH_INFO', $_ENV) - && $_ENV['PATH_INFO'] - ? $_ENV['PATH_INFO'] - : $_GET['PATH_INFO'] - ) - )) - ); +// mod_redirect can do some weird things when php is run in cgi mode + $keys = preg_grep('/^REDIRECT_/', array_keys($_SERVER)); + if (!empty($keys)) { + foreach ($keys as $key) { + $key = substr($key, 9); + if (!array_key_exists($key, $_SERVER)) + $_SERVER[$key] = $_SERVER["REDIRECT_$key"]; + } + } // Clean the document root variable and make sure it doesn't have a trailing slash $_SERVER['DOCUMENT_ROOT'] = preg_replace('/\/+$/', '', $_SERVER['DOCUMENT_ROOT']); @@ -94,6 +81,29 @@ exit; } +/** + * $Path is an array of PATH_INFO passed into the script via mod_rewrite or some + * other lesser means. It contains most of the information required for + * figuring out what functions the user wants to access. + * + * @global array $GLOBALS['Path'] + * @name $Path +/**/ + global $Path; + $Path = explode('/', preg_replace('/^\/+/', '', // Remove leading slashes + preg_replace('/[\s]+/', ' ', // Convert extra whitespace + // Grab the path info from various different places. + array_key_exists('PATH_INFO', $_SERVER) + && $_SERVER['PATH_INFO'] + ? $_SERVER['PATH_INFO'] + : (array_key_exists('PATH_INFO', $_ENV) + && $_ENV['PATH_INFO'] + ? $_ENV['PATH_INFO'] + : $_GET['PATH_INFO'] + ) + )) + ); + // Load the database connection routines require_once 'includes/db.php'; Index: mythplugins/mythweb/includes/mobile.php =================================================================== --- mythplugins/mythweb/includes/mobile.php (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweb/includes/mobile.php (.../branches/release-0-19-fixes) (revision 10931) @@ -74,58 +74,56 @@ * If you don't know the screensize of some mobile terminal then use * an empty array or approximate dimensions. */ - $mobiles = array(/* Phones using the Series 60 platform, e.g. Nokia 3650 and 6600. */ - 'Series 60' => array('width' => 176, 'height' => 208), - 'Series60' => array('width' => 176, 'height' => 208), - 'C500' => array('width'=>176, 'height'=> 220), // SPV C500 + $mobiles = array( + /* Phones using the Series 60 platform, e.g. Nokia 3650 and 6600. */ + 'Series 60' => array('width' => 176, 'height' => 208), + 'Series60' => array('width' => 176, 'height' => 208), + 'C500' => array('width'=>176, 'height'=> 220), // SPV C500 + /* Phones using the Series 90 platform, e.g. Nokia 7710. */ + 'Series 90' => array('width' => 640, 'height' => 320), + 'Series90' => array('width' => 640, 'height' => 320), + /* The following strings are added for the Palm browser WebPro + * WebPro sometimes supplies the screen dimensions, but sometimes not + * but we try to detect the best as possible */ + '240x320' => array('width' => 240, 'height' => 320), // PocketPC IE + '320x320' => array('width' => 320, 'height' => 320), // For all Palm Tungsten models + '320x480' => array('width' => 320, 'height' => 480), // For Palm Tungsten T + '480x320' => array('width' => 480, 'height' => 320), // For Palm Tungsten T + '320x480x16' => array('width' => 320, 'height' => 480), // For Palm Tungsten T + '480x320x16' => array('width' => 480, 'height' => 320), // For Palm Tungsten T + '320x320x16' => array('width' => 320, 'height' => 320), + 'WebPro' => array('width' => 320, 'height' => 320), // For all Palm Tungsten models + /* A generic mobile phone using Symbian OS. All Symbian phones don't + * necessarily have the same screen size so if you want to include + * some specific Symbian phones then place them above this line. */ + 'Symbian' => array('width' => 176, 'height' => 208), - /* Phones using the Series 90 platform, e.g. Nokia 7710. */ - 'Series 90' => array('width' => 640, 'height' => 320), - 'Series90' => array('width' => 640, 'height' => 320), + 'Nokia' => array(), // Nokia phones and emulators + 'Eric' => array(), // Ericsson WAP phones and emulators + 'WapI' => array(), // Ericsson WapIDE 2.0 + 'MC21' => array(), // Ericsson MC218 + 'AUR ' => array(), // Ericsson R320 + 'R380' => array(), // Ericsson R380 + 'UP.B' => array(), // UP.Browser + 'WinW' => array(), // WinWAP browser + 'UPG1' => array(), // UP.SDK 4.0 + 'upsi' => array(), // another kind of UP.Browser ?? + 'QWAP' => array(), // unknown QWAPPER browser + 'Jigs' => array(), // unknown JigSaw browser + 'Java' => array(), // unknown Java based browser + 'Alca' => array(), // unknown Alcatel-BE3 browser (UP based?) + 'MITS' => array(), // unknown Mitsubishi browser + 'MOT-' => array(), // unknown browser (UP based?) + 'My S' => array(), // unknown Ericsson devkit browser ? + 'WAPJ' => array(), // Virtual WAPJAG www.wapjag.de + 'fetc' => array(), // fetchpage.cgi Perl script from www.wapcab.de + 'ALAV' => array(), // yet another unknown UP based browser ? + 'Wapa' => array(), // another unknown browser (Web based "Wapalyzer"?) + 'LGE-' => array(), // LG phones - /* The following strings are added for the Palm browser WebPro - * WebPro sometimes supplies the screen dimensions, but sometimes not - * but we try to detect the best as possible - */ - '320x480' => array('width' => 320, 'height' => 480), // For Palm Tungsten T - '480x320' => array('width' => 480, 'height' => 320), // For Palm Tungsten T - '320x320' => array('width' => 320, 'height' => 320), // For all Palm Tungsten models - '320x480x16' => array('width' => 320, 'height' => 480), // For Palm Tungsten T - '480x320x16' => array('width' => 480, 'height' => 320), // For Palm Tungsten T - '320x320x16' => array('width' => 320, 'height' => 320), - 'WebPro' => array('width' => 320, 'height' => 320), // For all Palm Tungsten models - - /* A generic mobile phone using Symbian OS. All Symbian phones don't - * necessarily have the same screen size so if you want to include - * some specific Symbian phones then place them above this line. */ - 'Symbian' => array('width' => 176, 'height' => 208), - - 'Nokia' => array(), // Nokia phones and emulators - 'Eric' => array(), // Ericsson WAP phones and emulators - 'WapI' => array(), // Ericsson WapIDE 2.0 - 'MC21' => array(), // Ericsson MC218 - 'AUR ' => array(), // Ericsson R320 - 'R380' => array(), // Ericsson R380 - 'UP.B' => array(), // UP.Browser - 'WinW' => array(), // WinWAP browser - 'UPG1' => array(), // UP.SDK 4.0 - 'upsi' => array(), // another kind of UP.Browser ?? - 'QWAP' => array(), // unknown QWAPPER browser - 'Jigs' => array(), // unknown JigSaw browser - 'Java' => array(), // unknown Java based browser - 'Alca' => array(), // unknown Alcatel-BE3 browser (UP based?) - 'MITS' => array(), // unknown Mitsubishi browser - 'MOT-' => array(), // unknown browser (UP based?) - 'My S' => array(), // unknown Ericsson devkit browser ? - 'WAPJ' => array(), // Virtual WAPJAG www.wapjag.de - 'fetc' => array(), // fetchpage.cgi Perl script from www.wapcab.de - 'ALAV' => array(), // yet another unknown UP based browser ? - 'Wapa' => array(), // another unknown browser (Web based "Wapalyzer"?) - 'LGE-' => array(), // LG phones - - /* For debugging: you can try out the mobile mode without a mobile phone. - * Replace 'Opera' with your browser. Comment out for release version. */ - //'Opera' => array('width' => 176, 'height' => 208) + /* For debugging: you can try out the mobile mode without a mobile phone. + * Replace 'Opera' with your browser. Comment out for release version. */ + //'Opera' => array('width' => 176, 'height' => 208) ); /* Scan through $mobiles and try to find matching user agent. */ Index: mythplugins/mythweb/includes/recording_schedules.php =================================================================== --- mythplugins/mythweb/includes/recording_schedules.php (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweb/includes/recording_schedules.php (.../branches/release-0-19-fixes) (revision 10931) @@ -68,10 +68,14 @@ // Cleanup mysql_free_result($result); +// Initialize + global $Scheduled_Recordings, $Num_Conflicts, $Num_Scheduled; + $Scheduled_Recordings = array(); + $Num_Conflicts = 0; + $Num_Scheduled = 0; + // Load all of the scheduled recordings. We will need them at some point, so we // might as well get it overwith here. - global $Scheduled_Recordings, $Num_Conflicts, $Num_Scheduled; - $Scheduled_Recordings = array(); foreach (get_backend_rows('QUERY_GETALLPENDING', 2) as $key => $program) { // The offset entry if ($key === 'offset') { Index: mythplugins/mythweb/includes/session.php =================================================================== --- mythplugins/mythweb/includes/session.php (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweb/includes/session.php (.../branches/release-0-19-fixes) (revision 10931) @@ -19,8 +19,8 @@ // Start the session session_name('mythweb_id'); - session_set_cookie_params(60 * 60 * 30, '/'); // 30 day timeout on cookies - ini_set('session.gc_maxlifetime', 60 * 60 * 30); // ... and sessions + session_set_cookie_params(60 * 60 * 24 * 365, '/'); // 1 year timeout on cookies + ini_set('session.gc_maxlifetime', 60 * 60 * 24 * 30); // 30 day timeout on sessions session_set_save_handler('sess_do_nothing', 'sess_do_nothing', 'sess_read', 'sess_write', 'sess_destroy', 'sess_gc'); session_start(); Index: mythplugins/mythweb/modules/weather/handler.php =================================================================== --- mythplugins/mythweb/modules/weather/handler.php (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweb/modules/weather/handler.php (.../branches/release-0-19-fixes) (revision 10931) @@ -222,8 +222,10 @@ $data = explode("|", $data); for($i = 0;$i<5;$i++) { - $forecast = new Forecast($data[5 + $i],$data[$i]); - $forecast->dayofweek = $data[$i]; + # mktime uses 0-6; msnbc gives us 1-7; adjust msnbc to match mktime + $dayofweek = $data[$i] - 1; + $forecast = new Forecast($data[5 + $i],$dayofweek); + $forecast->dayofweek = $dayofweek; list($forecast->DescImage,$forecast->DescText) = getImageAndDescFromId($data[15 + $i]); $forecast->DescImage = (strlen($forecast->DescImage) > 0) ? $forecast->DescImage : "unknown.png"; $forecast->DescText = (strlen($forecast->DescText) > 0) ? $forecast->DescText : t('Unknown') . " (" . $data[15+$i] . ")"; Index: mythplugins/mythweb/modules/status/handler.php =================================================================== --- mythplugins/mythweb/modules/status/handler.php (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweb/modules/status/handler.php (.../branches/release-0-19-fixes) (revision 10931) @@ -18,14 +18,17 @@ $masterhost = get_backend_setting('MasterServerIP'); $statusport = get_backend_setting('BackendStatusPort'); +// XML mode? + $xml_param = ($Path[1] == 'xml') ? '/xml' : ''; + // Make sure the content is interpreted as UTF-8 header('Content-Type: text/html; charset=UTF-8'); // Load the status page if (function_exists('file_get_contents')) - $status = file_get_contents("http://$masterhost:$statusport"); + $status = file_get_contents("http://$masterhost:$statusport$xml_param"); else - $status = implode("\n", file("http://$masterhost:$statusport")); + $status = implode("\n", file("http://$masterhost:$statusport$xml_param")); // Extract the page title preg_match('#(.+?)#s', $status, $title); Index: mythplugins/mythweb/modules/backend_log/handler.php =================================================================== --- mythplugins/mythweb/modules/backend_log/handler.php (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweb/modules/backend_log/handler.php (.../branches/release-0-19-fixes) (revision 10931) @@ -16,7 +16,7 @@ // Where to start searching from $_GET['start'] = intVal($_GET['start']); if ($_GET['start'] < 1) - $_GET['start'] = 1; + $_GET['start'] = 0; // How many entries to show? $_GET['show'] = intVal($_GET['show']); Index: mythplugins/mythweb/modules/tv/upcoming.php =================================================================== --- mythplugins/mythweb/modules/tv/upcoming.php (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweb/modules/tv/upcoming.php (.../branches/release-0-19-fixes) (revision 10931) @@ -103,8 +103,9 @@ continue; } // Skip deactivated shows? - elseif (!$_SESSION['scheduled_recordings']['disp_deactivated']) { - continue; + elseif ($show->recstatus != 'Recording') { + if (!$_SESSION['scheduled_recordings']['disp_deactivated']) + continue; } // Assign a reference to this show to the various arrays $all_shows[] =& $Scheduled_Recordings[$channum][$starttime][$key]; Index: mythplugins/mythweb/modules/tv/recorded.php =================================================================== --- mythplugins/mythweb/modules/tv/recorded.php (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweb/modules/tv/recorded.php (.../branches/release-0-19-fixes) (revision 10931) @@ -128,9 +128,21 @@ continue; // Get the length (27 == recendts; 26 == recstartts) $length = $record[27] - $record[26]; - // Keep track of the total time and disk space used + // Keep track of the total time and disk space used (9 == fs_high; 10 == fs_low) $Total_Time += $length; - $Total_Used += ($record[9] + ($record[10] < 0)) * 4294967296 + $record[10]; // 9 == fs_high; 10 == fs_low; + if (function_exists('gmp_add')) { + // GMP functions should work better with 64 bit numbers. + $size = gmp_add($record[10], + gmp_mul('4294967296', + gmp_add($record[9], $record[10] < 0 ? '1' : '0') + ) + ); + $Total_Used = gmp_strval(gmp_add($Total_Used, $size)); + } + else { + // This is inaccurate, but it's the best we can get without GMP. + $Total_Used += ($record[9] + ($record[10] < 0)) * 4294967296 + $record[10]; + } // keep track of their names and how many episodes we have recorded $Total_Programs++; $Groups[$record[30]]++; @@ -223,8 +235,28 @@ // How much free disk space on the backend machine? list($size_high, $size_low, $used_high, $used_low) = explode(backend_sep, backend_command('QUERY_FREE_SPACE')); - define(disk_size, (($size_high + ($size_low < 0)) * 4294967296 + $size_low) * 1024); - define(disk_used, (($used_high + ($used_low < 0)) * 4294967296 + $used_low) * 1024); + if (function_exists('gmp_add')) { + // GMP functions should work better with 64 bit numbers. + $size = gmp_mul('1024', + gmp_add($size_low, + gmp_mul('4294967296', + gmp_add($size_high, $size_low < 0 ? '1' : '0')) + ) + ); + define(disk_size, gmp_strval($size)); + $size = gmp_mul('1024', + gmp_add($used_low, + gmp_mul('4294967296', + gmp_add($used_high, $used_low < 0 ? '1' : '0')) + ) + ); + define(disk_used, gmp_strval($size)); + } + else { + // This is inaccurate, but it's the best we can get without GMP. + define(disk_size, (($size_high + ($size_low < 0)) * 4294967296 + $size_low) * 1024); + define(disk_used, (($used_high + ($used_low < 0)) * 4294967296 + $used_low) * 1024); + } // Load the class for this page require_once theme_dir.'tv/recorded.php'; Index: mythplugins/mythweb/.htaccess =================================================================== --- mythplugins/mythweb/.htaccess (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweb/.htaccess (.../branches/release-0-19-fixes) (revision 10931) @@ -22,6 +22,7 @@ # AuthName "MythTV" # AuthDigestFile /var/www/htdigest # Require valid-user +# BrowserMatch "MSIE" AuthDigestEnableQueryStringHack=On # MythTV now uses the correct file suffix for mpeg files, so all .nuv files # should actually be NuppleVideo. However, apache probably doesn't know what @@ -66,8 +67,6 @@ php_value memory_limit 32M - php_value session.save_path php_sessions - php_value output_buffering 4096 php_value register_globals 0 php_value magic_quotes_gpc 0 Index: mythplugins/mythweb/js/debug.js =================================================================== --- mythplugins/mythweb/js/debug.js (.../tags/release-0-19) (revision 0) +++ mythplugins/mythweb/js/debug.js (.../branches/release-0-19-fixes) (revision 10931) @@ -0,0 +1,24 @@ +/** + * A random assortment of javascript debug routines + * + * @url $URL$ + * @date $Date$ + * @version $Revision$ + * @author $Author$ + * @copyright Silicon Mechanics + * @license LGPL + * + * @package SiMech + * @subpackage Javascript + * +/**/ + + var debug_window_handle; +// Create a debug window and debug into it + function debug_window(string) { + if (!debug_window_handle || debug_window_handle.closed) { + debug_window_handle = window.open('', 'Debug Window','scrollbars, resizable, width=400, height=600'); + debug_window_handle.document.write(''); + } + debug_window_handle.document.write('
'+string+'

'); + } Property changes on: mythplugins/mythweb/js/debug.js ___________________________________________________________________ Name: svn:eol-style + native Name: svn:mime-type + text/x-javascript Name: svn:keywords + Date Revision Author HeadURL Index: mythplugins/mythweb/js/browser.js =================================================================== --- mythplugins/mythweb/js/browser.js (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweb/js/browser.js (.../branches/release-0-19-fixes) (revision 10931) @@ -215,14 +215,18 @@ browser.is_css = (document.body && document.body.style) browser.is_w3c = (browser.is_css && browser.getElementById) -// Cookie support - var tmp = document.cookie; - document.cookie = 'cookies=true'; - browser.cookies = (document.cookie) ? true : false; - document.cookie = tmp; +// Cookie support -- only create a cookie if there isn't one already. It seems +// that doing this can override the exipiration info in existing cookies. + browser.cookies = (document.cookie) ? true : false; + if (!browser.cookies) { + var tmp = document.cookie; + document.cookie = 'cookie_test=true'; + browser.cookies = (document.cookie) ? true : false; + document.cookie = tmp; + } // Java support - browser.java = navigator.javaEnabled(); + browser.java = navigator.javaEnabled(); /****************************** Plugin Support ******************************/ Index: mythplugins/mythweb/README =================================================================== --- mythplugins/mythweb/README (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweb/README (.../branches/release-0-19-fixes) (revision 10931) @@ -1,18 +1,12 @@ This is the README file for the MythWeb package. -January 17, 2006 +March 6, 2006 -Version: .19 pre -(c) 2002-2006 Thor Sigvaldason +Version: .19 +(c) 2002-2006 Chris Petersen Isaac Richards - Chris Petersen + Thor Sigvaldason + and others... (see mythtv.org commit logs for details) -with contributions from many people including: - -Michael Kedl -Jonathan Kolb -Kenneth Aafloy - MythWeb is distributed under the GNU GENERAL PUBLIC LICENSE version 2, and where noted with the @license tag, the LESSER GENERAL PUBLIC LICENSE version 2. Please see http://www.gnu.org for details and the specific text of the license. @@ -63,10 +57,22 @@ In order for the included .htaccess to work properly, you will need to set apache's "AllowOverride" setting to "All" (or at least "Options") for -the root mythweb directory. This directive lives within tags, -so make sure you're changing the setting for the correct directory. You will -also need to make sure that the following apache modules are enabled: +the root mythweb directory. This directive lives within tags, +so make sure you're changing the setting for the correct directory. Please +keep in mind that most distros correctly disable everything for , +and then later override those with something like . +The simplest way to do this is to put a file into /etc/httpd/conf.d (or +whatever your distro calls it) containing something like: + + Options FollowSymLinks + AllowOverride All + + +Just make sure that the path points to your MythWeb installation, since that +will likely differ from system to system. You will also need to make sure that +the following apache modules are enabled: + mod_env mod_rewrite Index: mythplugins/mythdvd/mtd/jobthread.cpp =================================================================== --- mythplugins/mythdvd/mtd/jobthread.cpp (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythdvd/mtd/jobthread.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -11,6 +11,7 @@ #include #include #include +#include #include using namespace std; Index: mythplugins/mythdvd/mtd/mtd.cpp =================================================================== --- mythplugins/mythdvd/mtd/mtd.cpp (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythdvd/mtd/mtd.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -8,6 +8,7 @@ */ +#include #include #include #include Index: mythplugins/mythdvd/mtd/logging.cpp =================================================================== --- mythplugins/mythdvd/mtd/logging.cpp (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythdvd/mtd/logging.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -9,6 +9,7 @@ */ #include "logging.h" +#include #include #include Index: mythplugins/mythmusic/mythmusic/vorbisdecoder.cpp =================================================================== --- mythplugins/mythmusic/mythmusic/vorbisdecoder.cpp (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythmusic/mythmusic/vorbisdecoder.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -12,6 +12,7 @@ #include "metadata.h" #include "metaiooggvorbiscomment.h" +#include #include // static functions for OggVorbis @@ -240,8 +241,13 @@ seekTime = -1.0; } +#ifdef WORDS_BIGENDIAN + len = ov_read(&oggfile, (char *) (output_buf + output_at), bks, 1, 2, 1, + §ion); +#else len = ov_read(&oggfile, (char *) (output_buf + output_at), bks, 0, 2, 1, §ion); +#endif if (len > 0) { bitrate = ov_bitrate_instant(&oggfile) / 1000; Index: mythplugins/mythmusic/mythmusic/flacdecoder.cpp =================================================================== --- mythplugins/mythmusic/mythmusic/flacdecoder.cpp (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythmusic/mythmusic/flacdecoder.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -12,6 +12,7 @@ #include "metadata.h" #include "metaioflacvorbiscomment.h" +#include #include #include @@ -102,7 +103,11 @@ for (channel = 0; channel < chan; channel++) { sample = (FLAC__int8)buffer[channel][cursamp]; +#ifdef WORDS_BIGENDIAN + *(output_buf + output_at++) = ((sample >> 8) & 0xff); +#else *(output_buf + output_at++) = ((sample >> 0) & 0xff); +#endif output_bytes += 1; } } @@ -114,8 +119,13 @@ for (channel = 0; channel < chan; channel++) { sample = (FLAC__int16)buffer[channel][cursamp]; +#ifdef WORDS_BIGENDIAN + *(output_buf + output_at++) = ((sample >> 8) & 0xff); *(output_buf + output_at++) = ((sample >> 0) & 0xff); +#else + *(output_buf + output_at++) = ((sample >> 0) & 0xff); *(output_buf + output_at++) = ((sample >> 8) & 0xff); +#endif output_bytes += 2; } } Index: mythplugins/mythmusic/mythmusic/maddecoder.cpp =================================================================== --- mythplugins/mythmusic/mythmusic/maddecoder.cpp (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythmusic/mythmusic/maddecoder.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -16,6 +16,7 @@ #include #include "metaioid3v2.h" +#include #include #define XING_MAGIC (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g') @@ -407,7 +408,7 @@ flush(TRUE); if (output()) { - output()->Drain(); + output()->Drain(); } done = TRUE; @@ -488,15 +489,25 @@ flush(); } sample = fix_sample(16, *left++); +#ifdef WORDS_BIGENDIAN + *(output_buf + output_at++) = ((sample >> 8) & 0xff); *(output_buf + output_at++) = ((sample >> 0) & 0xff); +#else + *(output_buf + output_at++) = ((sample >> 0) & 0xff); *(output_buf + output_at++) = ((sample >> 8) & 0xff); +#endif output_bytes += 2; if (channels == 2) { sample = fix_sample(16, *right++); +#ifdef WORDS_BIGENDIAN + *(output_buf + output_at++) = ((sample >> 8) & 0xff); *(output_buf + output_at++) = ((sample >> 0) & 0xff); +#else + *(output_buf + output_at++) = ((sample >> 0) & 0xff); *(output_buf + output_at++) = ((sample >> 8) & 0xff); +#endif output_bytes += 2; } } Index: mythplugins/mythweather/mythweather/weather.cpp =================================================================== --- mythplugins/mythweather/mythweather/weather.cpp (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythweather/mythweather/weather.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -2571,6 +2571,14 @@ return false; } + int imageCount = 5; + QString imagesList = parseData(tempData, "imagenames = new Array( '", ";"); + if (imagesList != "") + { + QStringList imageURLs = QStringList::split(",", imagesList); + imageCount = imageURLs.size(); + } + QString fileprefix = MythContext::GetConfDir(); QDir dir(fileprefix); @@ -2587,13 +2595,13 @@ cerr << "MythWeather: Map File Prefix: " << fileprefix << endl; // delete existing radar maps - for (int x = 1; x <= 6; x++) + for (int x = 1; x <= 10; x++) QFile::remove(QString(fileprefix + "/radar%1.jpg").arg(x)); if (debug) cerr << "MythWeather: Copying Map Files from Server (" << imageLoc << ")...\n"; - for (int x = 1; x <= 6; x++) + for (int x = 1; x <= imageCount; x++) { QString sFile = QString(fileprefix + "/radar%1.jpg").arg(x); sURL = QString("http://image.weather.com" + imageLoc + "%1L.jpg").arg(x); Index: mythplugins/mythcontrols/mythcontrols/mythcontrols.cpp =================================================================== --- mythplugins/mythcontrols/mythcontrols/mythcontrols.cpp (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythcontrols/mythcontrols/mythcontrols.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -46,22 +46,6 @@ #include "keygrabber.h" -static QMap FindContexts(const QString &context) -{ - QMap retval; - retval.clear(); - if (context != JUMP_CONTEXT) retval[-1] = JUMP_CONTEXT; - retval[0] = context; - if (context != JUMP_CONTEXT && context != GLOBAL_CONTEXT) - { - if (context == "TV Editting") - retval[1] = "TV Playback"; - retval[2] = GLOBAL_CONTEXT; - if (context != "qt") - retval[3] = "qt"; - } - return retval; -} static const QString KeyToDisplay(const QString key) { @@ -838,7 +822,11 @@ refreshKeyInformation(); } -void MythControls::addBindings(QDict &bindings, const QString &context, const QString &contextParent, int bindlevel) + + +void MythControls::addBindings(QDict &bindings, + const QString &context, + const QString &contextParent, int bindlevel) { QStringList *actions = key_bindings->getActions(context); @@ -872,18 +860,13 @@ BindingList *MythControls::getKeyBindings(const QString &context) { + QStringList keys; QDict bindings; bindings.clear(); - QMap contextList = FindContexts(context); - for (QMap::iterator it = contextList.begin(); it != contextList.end(); ++it) - { - int level = it.key(); - QString curcontext = it.data(); - addBindings(bindings, curcontext, context, level); - } + for (size_t i = 0; i < contexts.size(); i++) + addBindings(bindings, contexts[i], context, i); - QStringList keys; for (QDictIterator it(bindings); it.current(); ++it) { Index: mythplugins/mythcontrols/mythcontrols/actionset.cpp =================================================================== --- mythplugins/mythcontrols/mythcontrols/actionset.cpp (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythcontrols/mythcontrols/actionset.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -139,13 +139,19 @@ /* method description in header */ QStringList * ActionSet::actionStrings(const QString &context_name) const { - QStringList *action_strings = new QStringList(); - QDictIterator it(*(_contexts[context_name])); + Context *c = _contexts[context_name]; - for (; it.current(); ++it) - action_strings->append(it.currentKey()); + if (c == NULL) return NULL; + else + { + QStringList *action_strings = new QStringList(); + QDictIterator it(*(_contexts[context_name])); + + for (; it.current(); ++it) + action_strings->append(it.currentKey()); - return action_strings; + return action_strings; + } } Index: mythplugins/mythcontrols/mythcontrols/keybindings.h =================================================================== --- mythplugins/mythcontrols/mythcontrols/keybindings.h (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythcontrols/mythcontrols/keybindings.h (.../branches/release-0-19-fixes) (revision 10931) @@ -65,6 +65,8 @@ /** * @brief Get a list of the context names. * @return A list of the context names. + * @note The returned list is a copy and can be modified without + * side-effects. */ inline QStringList * getContexts() const { Index: mythplugins/mythvideo/mythvideo/videomanager.h =================================================================== --- mythplugins/mythvideo/mythvideo/videomanager.h (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythvideo/mythvideo/videomanager.h (.../branches/release-0-19-fixes) (revision 10931) @@ -30,7 +30,7 @@ public: VideoManager(MythMainWindow *parent, const char *name = 0); ~VideoManager(void); - void VideoManager::processEvents() { qApp->processEvents(); } + void processEvents() { qApp->processEvents(); } public slots: void slotManualIMDB(); Index: mythplugins/mythvideo/mythvideo/videoselected.h =================================================================== --- mythplugins/mythvideo/mythvideo/videoselected.h (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythvideo/mythvideo/videoselected.h (.../branches/release-0-19-fixes) (revision 10931) @@ -35,7 +35,7 @@ VideoSelected(VideoList *lvideolist, MythMainWindow *parent, const char *name = 0, int index = 0); ~VideoSelected(); - void VideoSelected::processEvents() { qApp->processEvents(); } + void processEvents() { qApp->processEvents(); } protected slots: Index: mythplugins/mythphone/mythphone/sipfsm.h =================================================================== --- mythplugins/mythphone/mythphone/sipfsm.h (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythphone/mythphone/sipfsm.h (.../branches/release-0-19-fixes) (revision 10931) @@ -618,7 +618,7 @@ SipWatcher *CreateWatcherFsm(QString Url); SipIM *CreateIMFsm(QString Url="", QString callIdStr=""); void StopWatchers(); - void SipFsm::KickWatcher(SipUrl *Url); + void KickWatcher(SipUrl *Url); void SendIM(QString destUrl, QString CallId, QString imMsg); int numCalls(); int getPrimaryCall() { return primaryCall; }; Index: mythplugins/mythphone/mythphone/vxml.h =================================================================== --- mythplugins/mythphone/mythphone/vxml.h (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythphone/mythphone/vxml.h (.../branches/release-0-19-fixes) (revision 10931) @@ -10,7 +10,7 @@ { public: vxmlVariable(QString N, QString V); - vxmlVariable::vxmlVariable(QString N, short *wav, int S); + vxmlVariable(QString N, short *wav, int S); virtual ~vxmlVariable() {}; bool isType(QString t) { return (t == Type); }; QString getName() { return Name; }; Index: mythplugins/mythgame/mythgame/gamehandler.h =================================================================== --- mythplugins/mythgame/mythgame/gamehandler.h (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythgame/mythgame/gamehandler.h (.../branches/release-0-19-fixes) (revision 10931) @@ -106,7 +106,7 @@ protected: static GameHandler* GetHandler(RomInfo *rominfo); - static GameHandler* GameHandler::GetHandlerByName(QString systemname); + static GameHandler* GetHandlerByName(QString systemname); bool rebuild; int spandisks; Index: mythplugins/mythnews/mythnews/news-sites.xml =================================================================== --- mythplugins/mythnews/mythnews/news-sites.xml (.../tags/release-0-19) (revision 10931) +++ mythplugins/mythnews/mythnews/news-sites.xml (.../branches/release-0-19-fixes) (revision 10931) @@ -119,7 +119,7 @@ Slashdot - http://slashdot.org/slashdot.rss + http://rss.slashdot.org/Slashdot/slashdot http://slashdot.org/favicon.ico Index: mythtv/libs/libmythtv/dvbchannel.h =================================================================== --- mythtv/libs/libmythtv/dvbchannel.h (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/dvbchannel.h (.../branches/release-0-19-fixes) (revision 10931) @@ -60,11 +60,13 @@ { return chan_opts.pmt.HasTelevisionService(); } /// Returns true iff we have a faulty DVB driver that munges PMT bool HasCRCBug(void) const { return has_crc_bug; } + uint GetMinSignalMonitorDelay(void) const { return sigmon_delay; } // Commands bool SwitchToInput(const QString &inputname, const QString &chan); bool SwitchToInput(int newcapchannel, bool setstarting); bool Tune(const dvb_channel_t& channel, bool force_reset=false); + bool Retune(void); // Set/Get/Command just for SIScan/ScanWizardScanner void SetMultiplexID(int mplexid) { currentTID = mplexid; }; @@ -109,11 +111,18 @@ volatile int fd_frontend; ///< File descriptor for tuning hardware int cardnum; ///< DVB Card number bool has_crc_bug; ///< true iff our driver munges PMT + uint tuning_delay;///< Extra delay to add for broken drivers + uint sigmon_delay;///< Minimum delay between FE_LOCK checks int currentTID; ///< Stores mplexid from database bool first_tune; ///< Used to force hardware reset int nextcapchannel; ///< Signal an input change + + /// Last tuning options sent to hardware for retuning + DVBTuning retune_tuning; + /// Retuning adjustment, required so drivers don't ignore retune request + int retune_adj; }; #endif Index: mythtv/libs/libmythtv/NuppelVideoPlayer.h =================================================================== --- mythtv/libs/libmythtv/NuppelVideoPlayer.h (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/NuppelVideoPlayer.h (.../branches/release-0-19-fixes) (revision 10931) @@ -150,7 +150,8 @@ // Complicated gets long long CalcMaxFFTime(long long ff, bool setjump = true) const; long long CalcRWTime(long long rw) const; - void calcSliderPos(struct StatusPosInfo &posInfo); + void calcSliderPos(struct StatusPosInfo &posInfo, + bool paddedFields = false); /// Non-const gets OSD *GetOSD(void) { return osd; } @@ -297,6 +298,7 @@ bool DecodeFrame(struct rtframeheader *frameheader, unsigned char *strm, unsigned char *outbuf); + bool PrebufferEnoughFrames(void); void CheckPrebuffering(void); bool GetFrameNormal(int onlyvideo); bool GetFrameFFREW(void); @@ -309,7 +311,7 @@ bool DoRewind(void); // Private seeking stuff - void ClearAfterSeek(void); + void ClearAfterSeek(bool clearvideobuffers = true); bool FrameIsInMap(long long frameNumber, QMap &breakMap); void JumpToFrame(long long frame); void JumpToNetFrame(long long net) { JumpToFrame(framesPlayed + net); } @@ -543,6 +545,7 @@ QMap::Iterator deleteIter; QMap::Iterator blankIter; QMap::Iterator commBreakIter; + bool forcePositionMapSync; // Playback (output) speed control /// Lock for next_play_speed and next_normal_speed Index: mythtv/libs/libmythtv/osdlistbtntype.h =================================================================== --- mythtv/libs/libmythtv/osdlistbtntype.h (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/osdlistbtntype.h (.../branches/release-0-19-fixes) (revision 10931) @@ -1,3 +1,4 @@ +// -*- Mode: c++ -*- /* ============================================================ * File : uilistbtntype.h * Author: Renchi Raju @@ -22,38 +23,57 @@ #ifndef OSDLISTBTNTYPE_H #define OSDLISTBTNTYPE_H -#include "osdtypes.h" -#include "ttfont.h" +#include +using namespace std; + +// Qt headers #include #include #include #include +#include + +// MythTV headers +#include "osdtypes.h" +#include "ttfont.h" #include "generictree.h" +class OSDListBtnType; class OSDListBtnTypeItem; -class OSDListBtnType; +typedef vector OSDListBtnList; +typedef vector OSDListBtnItemList; class OSDGenericTree : public GenericTree { public: // This class will _not_ delete the image it's given, if any. - OSDGenericTree(OSDGenericTree *parent, const QString &name, - const QString &action = "", int check = -1, - OSDTypeImage *image = NULL, QString group = ""); + OSDGenericTree(OSDGenericTree *parent, const QString &name, + const QString &action = "", int check = -1, + OSDTypeImage *image = NULL, QString group = "") : + GenericTree(name), m_image(image), m_action(action), + m_group(group), m_checkable(check), m_parentButton(NULL) + { + m_group = (m_group.isEmpty()) ? action : m_group; + setSelectable(!action.isEmpty()); + if (parent) + parent->addNode(this); + } - OSDTypeImage *getImage(void) { return m_image; } - QString getAction(void) { return m_action; } - int getCheckable(void) { return m_checkable; } - QString getGroup(void) { return m_group; } + QString getAction(void) const { return m_action; } + QString getGroup(void) const { return m_group; } + int getCheckable(void) const { return m_checkable; } + + OSDTypeImage *getImage(void) { return m_image; } + OSDListBtnTypeItem *getParentButton(void) { return m_parentButton; } + void setParentButton(OSDListBtnTypeItem *button) - { m_parentButton = button; }; - OSDListBtnTypeItem *getParentButton(void) { return m_parentButton; }; + { m_parentButton = button; } private: - OSDTypeImage *m_image; - QString m_action; - int m_checkable; - QString m_group; + OSDTypeImage *m_image; + QString m_action; + QString m_group; + int m_checkable; OSDListBtnTypeItem *m_parentButton; }; @@ -62,53 +82,49 @@ { Q_OBJECT public: - OSDListTreeType(const QString &name, const QRect &area, - const QRect &levelsize, int levelspacing, - float wmult, float hmult); + OSDListTreeType(const QString &name, const QRect &area, + const QRect &levelsize, int levelspacing, + float wmult, float hmult); + ~OSDListTreeType(); - void Reinit(float wchange, float hchange, float wmult, float hmult); + bool IsVisible(void) const { return m_visible; } + + void SetFontActive(TTFFont *font) { m_active = font; } + void SetFontInactive(TTFFont *font) { m_inactive = font; } + void SetGroupCheckState(QString group, int newState = 0); + void SetSpacing(uint spacing) + { m_unbiasedspacing = (m_spacing = spacing) / m_wmult; } + void SetMargin(uint margin) + { m_unbiasedmargin = (m_margin = margin) / m_wmult; } + void SetItemRegColor(const QColor& beg, const QColor& end, uint alpha) + { m_itemRegBeg = beg; m_itemRegEnd = end; m_itemRegAlpha = alpha; } + void SetItemSelColor(const QColor& beg, const QColor& end, uint alpha) + { m_itemSelBeg = beg; m_itemSelEnd = end; m_itemSelAlpha = alpha; } + void SetVisible(bool visible) { m_visible = visible; } + void SetAsTree(OSDGenericTree *toplevel, vector *select = NULL); - void SetFontActive(TTFFont *font); - void SetFontInactive(TTFFont *font); - void SetSpacing(int spacing); - void SetMargin(int margin); - void SetItemRegColor(const QColor& beg, const QColor& end, uint alpha); - void SetItemSelColor(const QColor& beg, const QColor& end, uint alpha); - - void SetAsTree(OSDGenericTree *toplevel); - - OSDGenericTree *GetCurrentPosition(void); - + void Reinit(float wmult, float hmult); bool HandleKeypress(QKeyEvent *e); - void Draw(OSDSurface *surface, int fade, int maxfade, int xoff, int yoff); - bool IsVisible(void) { return m_visible; } - void SetVisible(bool visible) { m_visible = visible; } - signals: void itemSelected(OSDListTreeType *parent, OSDGenericTree *item); void itemEntered(OSDListTreeType *parent, OSDGenericTree *item); private: - void FillLevelFromTree(OSDGenericTree *item, OSDListBtnType *list); - OSDListBtnType *GetLevel(int levelnum); - void SetCurrentPosition(void); + void FillLevelFromTree(OSDGenericTree *item, uint levelnum); + OSDListBtnType *GetLevel(uint levelnum); + void EnterItem(void); + void SelectItem(void); - int levels; - int curlevel; - OSDGenericTree *treetop; OSDGenericTree *currentpos; + TTFFont *m_active; + TTFFont *m_inactive; - QPtrList listLevels; + OSDListBtnList listLevels; - OSDListBtnType *currentlevel; - - TTFFont *m_active; - TTFFont *m_inactive; - QColor m_itemRegBeg; QColor m_itemRegEnd; QColor m_itemSelBeg; @@ -116,62 +132,76 @@ uint m_itemRegAlpha; uint m_itemSelAlpha; - int m_spacing; - int m_margin; + uint m_spacing; + uint m_margin; + int m_levelspacing; - QRect m_totalarea; - QRect m_levelsize; - int m_levelspacing; + QRect m_totalarea; + QRect m_levelsize; - float m_wmult; - float m_hmult; + float m_unbiasedspacing; + float m_unbiasedmargin; + QRect m_unbiasedarea; + QRect m_unbiasedsize; - bool m_visible; - bool m_arrowAccel; + float m_wmult; + float m_hmult; + + int m_depth; + int m_levelnum; + bool m_visible; + bool m_arrowAccel; }; class OSDListBtnType : public OSDType { + friend class OSDListBtnTypeItem; Q_OBJECT + public: OSDListBtnType(const QString &name, const QRect& area, float wmult, float hmult, bool showScrollArrows = false); ~OSDListBtnType(); - void Reinit(float wchange, float hchange, float wmult, float hmult); + // General Gets + bool IsVisible() const { return m_visible; } + + // General Sets + void SetFontActive(TTFFont *font) { m_fontActive = font; } + void SetFontInactive(TTFFont *font) { m_fontInactive = font; } + void SetSpacing(int spacing) { m_itemSpacing = spacing; } + void SetMargin(int margin) { m_itemMargin = margin; } + void SetActive(bool active) { m_active = active; } + void SetVisible(bool vis) { m_visible = vis; } + void SetItemRegColor(const QColor& beg, const QColor& end, uint alpha) + { m_itemRegBeg = beg; m_itemRegEnd = end; m_itemRegAlpha = alpha; } + void SetItemSelColor(const QColor& beg, const QColor& end, uint alpha) + { m_itemSelBeg = beg; m_itemSelEnd = end; m_itemSelAlpha = alpha; } void SetGroupCheckState(QString group, int newState = 0); + void SetItemCurrent(const OSDListBtnTypeItem* item); + void SetItemCurrent(uint pos); - void SetFontActive(TTFFont *font); - void SetFontInactive(TTFFont *font); - void SetSpacing(int spacing); - void SetMargin(int margin); - void SetItemRegColor(const QColor& beg, const QColor& end, uint alpha); - void SetItemSelColor(const QColor& beg, const QColor& end, uint alpha); - - void Draw(OSDSurface *surface, int fade, int maxfade, int xoff, int yoff); - - void SetActive(bool active); - void Reset(); - - void SetItemCurrent(OSDListBtnTypeItem* item); - void SetItemCurrent(int pos); - OSDListBtnTypeItem* GetItemCurrent(); - OSDListBtnTypeItem* GetItemFirst(); - OSDListBtnTypeItem* GetItemNext(OSDListBtnTypeItem *item); + // Item Gets + int GetCount(void) const; + int GetItemPos(const OSDListBtnTypeItem* item) const; + int GetItemCurrentPos() const; + OSDListBtnTypeItem* GetItemCurrent(void); + OSDListBtnTypeItem* GetItemFirst(void); + OSDListBtnTypeItem* GetItemNext(const OSDListBtnTypeItem *item); OSDListBtnTypeItem* GetItemAt(int pos); - int GetItemPos(OSDListBtnTypeItem* item); - int GetCount(); - void MoveDown(); - void MoveUp(); + // Item Sets/Commands + void MoveDown(void); + void MoveUp(void); - bool IsVisible() { return m_visible; } - void SetVisible(bool vis) { m_visible = vis; } + // General Commands + void Draw(OSDSurface *surface, int fade, int maxfade, int xoff, int yoff); + void Reinit(float,float) {} + void Reset(void); private: - - void Init(); + void Init(void); void InitItem(OSDTypeImage &osdImg, uint width, uint height, QColor beg, QColor end, int alpha); void LoadPixmap(OSDTypeImage& pix, const QString& fileName); @@ -179,24 +209,35 @@ void InsertItem(OSDListBtnTypeItem *item); void RemoveItem(OSDListBtnTypeItem *item); - int m_order; - QRect m_rect; - QRect m_contentsRect; - QRect m_arrowsRect; + private: + int m_order; + QRect m_rect; + QRect m_contentsRect; + QRect m_arrowsRect; - float m_wmult; - float m_hmult; + float m_wmult; + float m_hmult; - int m_itemHeight; - int m_itemSpacing; - int m_itemMargin; - uint m_itemsVisible; + int m_itemHeight; + int m_itemSpacing; + int m_itemMargin; + uint m_itemsVisible; - bool m_active; - bool m_showScrollArrows; - bool m_showUpArrow; - bool m_showDnArrow; + bool m_active; + bool m_showScrollArrows; + bool m_showUpArrow; + bool m_showDnArrow; + bool m_initialized; + bool m_clearing; + bool m_visible; + QColor m_itemRegBeg; + QColor m_itemRegEnd; + QColor m_itemSelBeg; + QColor m_itemSelEnd; + uint m_itemRegAlpha; + uint m_itemSelAlpha; + OSDTypeImage m_itemRegPix; OSDTypeImage m_itemSelActPix; OSDTypeImage m_itemSelInactPix; @@ -209,43 +250,30 @@ OSDTypeImage m_checkHalfPix; OSDTypeImage m_checkFullPix; - QColor m_itemRegBeg; - QColor m_itemRegEnd; - QColor m_itemSelBeg; - QColor m_itemSelEnd; - uint m_itemRegAlpha; - uint m_itemSelAlpha; + TTFFont *m_fontActive; + TTFFont *m_fontInactive; - TTFFont* m_fontActive; - TTFFont* m_fontInactive; + int m_topIndx; + int m_selIndx; - bool m_initialized; - bool m_clearing; + OSDListBtnItemList m_itemList; - OSDListBtnTypeItem* m_topItem; - OSDListBtnTypeItem* m_selItem; - QPtrList m_itemList; + mutable QMutex m_update; - QMutex m_update; - - bool m_visible; - - friend class OSDListBtnTypeItem; - signals: - void itemSelected(OSDListBtnTypeItem* item); }; class OSDListBtnTypeItem { + friend class OSDListBtnType; public: - - enum CheckState { - NotChecked=0, + enum CheckState + { + NotChecked = 0, HalfChecked, - FullChecked + FullChecked, }; OSDListBtnTypeItem(OSDListBtnType* lbtype, const QString& text, @@ -253,41 +281,36 @@ bool showArrow = false, CheckState state = NotChecked); ~OSDListBtnTypeItem(); - OSDListBtnType* parent() const; - QString text() const; - const OSDTypeImage* pixmap() const; - bool checkable() const; - CheckState state() const; + OSDListBtnType* parent(void) const { return m_parent; } + QString text(void) const { return m_text; } + const OSDTypeImage* pixmap(void) const { return m_pixmap; } + bool checkable(void) const { return m_checkable; } + CheckState state(void) const { return m_state; } + QString getGroup(void) const { return m_group; } + void *getData(void) { return m_data; } - void setChecked(CheckState state); - void setData(void *data); - void* getData(); - void setGroup(QString group) { m_group = group; }; - QString getGroup(void) { return m_group; } + void setData(void *data) { m_data = data; } + void setGroup(QString grp) { m_group = grp; } + void setChecked(CheckState state) + { m_state = (m_checkable) ? state : m_state; } - void Reinit(float wchange, float hchange, float wmult, float hmult); - + void Reinit(float,float) {} void paint(OSDSurface *surface, TTFFont *font, int fade, int maxfade, int x, int y); protected: - OSDListBtnType *m_parent; - QString m_text; - OSDTypeImage *m_pixmap; - bool m_checkable; - CheckState m_state; - void *m_data; - QString m_group; - - QRect m_checkRect; - QRect m_pixmapRect; - QRect m_textRect; - QRect m_arrowRect; - - bool m_showArrow; - - friend class OSDListBtnType; + OSDTypeImage *m_pixmap; + void *m_data; + QString m_text; + QString m_group; + CheckState m_state; + bool m_showArrow; + bool m_checkable; + QRect m_checkRect; + QRect m_arrowRect; + QRect m_pixmapRect; + QRect m_textRect; }; Index: mythtv/libs/libmythtv/NuppelVideoPlayer.cpp =================================================================== --- mythtv/libs/libmythtv/NuppelVideoPlayer.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/NuppelVideoPlayer.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -147,6 +147,7 @@ hascommbreaktable(false), deleteIter(deleteMap.end()), blankIter(blankMap.end()), commBreakIter(commBreakMap.end()), + forcePositionMapSync(false), // Playback (output) speed control decoder_lock(true), next_play_speed(1.0f), next_normal_speed(true), @@ -747,6 +748,8 @@ SetDecoder(new IvtvDecoder(this, m_playbackinfo)); no_audio_out = true; // no audio with ivtv. audio_bits = 16; + audio_samplerate = 44100; + audio_channels = 2; } else if (forceVideoOutput == kVideoOutput_IVTV) { @@ -1113,7 +1116,7 @@ const unsigned char *NuppelVideoPlayer::GetScaledFrame(QSize &size) { QMutexLocker locker(&yuv_lock); - yuv_desired_size = size = QSize(size.width() & ~0x3, size.height() & ~0x3); + yuv_desired_size = size = QSize(size.width() & ~0x7, size.height() & ~0x7); if ((size.width() > 0) && (size.height() > 0)) { @@ -1626,8 +1629,8 @@ { // If we are using hardware decoding, so we've already done the // decoding; display the frame, but don't wait for A/V Sync. - videoOutput->PrepareFrame(buffer, ps); - videoOutput->Show(m_scan); + videoOutput->PrepareFrame(buffer, kScan_Intr2ndField); + videoOutput->Show(kScan_Intr2ndField); VERBOSE(VB_PLAYBACK, LOC + dbg + "skipping A/V wait."); } else @@ -1685,14 +1688,14 @@ if (diverge > MAXDIVERGE) { - // If audio is way ahead of video, adjust for it... + // If audio is way behind of video, adjust for it... // by cutting the frame rate in half for the length of this frame avsync_adjustment = frame_interval; lastsync = true; VERBOSE(VB_PLAYBACK, LOC + - QString("Audio is %1 frames ahead of video,\n" - "\t\t\tdoubling video frame interval.").arg(diverge)); + QString("Video is %1 frames ahead of audio,\n" + "\t\t\tdoubling video frame interval to slow down.").arg(diverge)); } if (audioOutput && normal_speed) @@ -1811,11 +1814,8 @@ videosync->Start(); } -void NuppelVideoPlayer::DisplayNormalFrame(void) +bool NuppelVideoPlayer::PrebufferEnoughFrames(void) { - video_actually_paused = false; - resetvideo = false; - prebuffering_lock.lock(); if (prebuffering) { @@ -1843,14 +1843,29 @@ } prebuffering_lock.unlock(); videosync->Start(); - return; + + return false; } prebuffering_lock.unlock(); //VERBOSE(VB_PLAYBACK, LOC + "fs: " + videoOutput->GetFrameStatus()); if (!videoOutput->EnoughPrebufferedFrames()) { - VERBOSE(VB_GENERAL, LOC + "prebuffering pause"); + if (videoOutput) + { + videoOutput->CheckFrameStates(); + if (videoOutput->hasMCAcceleration() || + videoOutput->hasIDCTAcceleration() || + videoOutput->hasVLDAcceleration()) + { + // Prebuffering fails w/XvMC's 8 surfaces.. + usleep(5000); + return false; + } + } + VERBOSE(VB_GENERAL, LOC + "prebuffering pause" + + videoOutput->GetFrameStatus()); + SetPrebuffering(true); #if FAST_RESTART if (!m_playing_slower && audio_channels <= 2) @@ -1861,7 +1876,7 @@ VERBOSE(VB_GENERAL, "playing slower due to falling behind..."); } #endif - return; + return false; } #if FAST_RESTART @@ -1877,6 +1892,25 @@ prebuffer_tries = 0; prebuffering_lock.unlock(); + return true; +} + +void NuppelVideoPlayer::DisplayNormalFrame(void) +{ + video_actually_paused = false; + resetvideo = false; + + if (!PrebufferEnoughFrames()) + { + // When going to switch channels + if (paused) + { + usleep(frame_interval); + DisplayPauseFrame(); + } + return; + } + videoOutput->StartDisplayingFrame(); VideoFrame *frame = videoOutput->GetLastShownFrame(); @@ -1920,7 +1954,7 @@ ShowText(); DisplaySubtitles(); } - else if (osdHasSubtitles || nonDisplayedSubtitles.size() > 20) + else if (osdHasSubtitles) { ClearSubtitles(); } @@ -2176,7 +2210,10 @@ } if (eof) + { discontinuity = true; + ClearSubtitles(); + } livetvchain->SetProgram(pginfo); @@ -2199,6 +2236,7 @@ } if (IsErrored()) { + VERBOSE(VB_IMPORTANT, LOC_ERR + "SwitchToProgram failed."); eof = true; return; } @@ -2265,6 +2303,8 @@ ringBuffer->Pause(); ringBuffer->WaitForPause(); + ClearSubtitles(); + livetvchain->SetProgram(pginfo); ringBuffer->Reset(true); @@ -2284,6 +2324,7 @@ if (errored || !GetDecoder()) { + VERBOSE(VB_IMPORTANT, LOC_ERR + "JumpToProgram failed."); errored = true; return; } @@ -2471,6 +2512,12 @@ JumpToProgram(); } + if (forcePositionMapSync) + { + forcePositionMapSync = false; + GetDecoder()->SyncPositionMap(); + } + if (IsErrored() || (nvr_enc && nvr_enc->GetErrorStatus())) { VERBOSE(VB_IMPORTANT, LOC_ERR + "Unknown error, exiting decoder"); @@ -3246,7 +3293,10 @@ GetDecoder()->DoFastForward(desiredFrame); GetDecoder()->setExactSeeks(exactseeks); - ClearAfterSeek(); + // Note: The video output will be reset by what the the decoder + // does, so we only need to reset the audio, subtitles, etc. + ClearAfterSeek(false); + lastSkipTime = time(NULL); return true; } @@ -3291,19 +3341,24 @@ } #endif -/** \fn NuppelVideoPlayer::ClearAfterSeek(void) +/** \fn NuppelVideoPlayer::ClearAfterSeek(bool) * \brief This is to support seeking... * * This resets the output classes and discards all * frames no longer being used by the decoder class. * * Note: caller should not hold any locks + * + * \param clearvideobuffers This clears the videooutput buffers as well, + * this is only safe if no old frames are + * required to continue decoding. */ -void NuppelVideoPlayer::ClearAfterSeek(void) +void NuppelVideoPlayer::ClearAfterSeek(bool clearvideobuffers) { - VERBOSE(VB_PLAYBACK, LOC + "ClearAfterSeek()"); + VERBOSE(VB_PLAYBACK, LOC + "ClearAfterSeek("<ClearAfterSeek(); + if (clearvideobuffers) + videoOutput->ClearAfterSeek(); for (int i = 0; i < MAXTBUFFER; i++) txtbuffers[i].timecode = 0; @@ -4398,6 +4453,8 @@ hascommbreaktable = !commBreakMap.isEmpty(); SetCommBreakIter(); commBreakMapLock.unlock(); + + forcePositionMapSync = true; } bool NuppelVideoPlayer::RebuildSeekTable(bool showPercentage, StatusCallback cb, void* cbData) @@ -4541,7 +4598,8 @@ return (int)((float)(written - played) / video_frame_rate); } -void NuppelVideoPlayer::calcSliderPos(struct StatusPosInfo &posInfo) +void NuppelVideoPlayer::calcSliderPos(struct StatusPosInfo &posInfo, + bool paddedFields) { posInfo.desc = ""; posInfo.position = 0; @@ -4588,15 +4646,23 @@ int ssecs = (playbackLen - shours * 3600 - smins * 60); QString text1, text2; - if (shours > 0) + if (paddedFields) { - text1.sprintf("%d:%02d:%02d", phours, pmins, psecs); - text2.sprintf("%d:%02d:%02d", shours, smins, ssecs); + text1.sprintf("%02d:%02d:%02d", phours, pmins, psecs); + text2.sprintf("%02d:%02d:%02d", shours, smins, ssecs); } else { - text1.sprintf("%d:%02d", pmins, psecs); - text2.sprintf("%d:%02d", smins, ssecs); + if (shours > 0) + { + text1.sprintf("%d:%02d:%02d", phours, pmins, psecs); + text2.sprintf("%d:%02d:%02d", shours, smins, ssecs); + } + else + { + text1.sprintf("%d:%02d", pmins, psecs); + text2.sprintf("%d:%02d", smins, ssecs); + } } posInfo.desc = QObject::tr("%1 of %2").arg(text1).arg(text2); @@ -4654,6 +4720,7 @@ if (commBreakIter.key() == totalFrames) { + VERBOSE(VB_IMPORTANT, LOC + "Skipping commercial to end of file"); eof = true; } else @@ -4721,7 +4788,7 @@ QString message = "COMMFLAG_REQUEST "; message += m_playbackinfo->chanid + " " + - m_playbackinfo->startts.toString(Qt::ISODate); + m_playbackinfo->recstartts.toString(Qt::ISODate); RemoteSendMessage(message); return false; @@ -5018,7 +5085,7 @@ QImage scaledImage = qImage.smoothScale(rect->w, rect->h); OSDTypeImage* image = new OSDTypeImage(); - image->SetPosition(QPoint(rect->x, rect->y)); + image->SetPosition(QPoint(rect->x, rect->y), hmult, vmult); image->LoadFromQImage(scaledImage); subtitleOSD->AddType(image); Index: mythtv/libs/libmythtv/NuppelVideoRecorder.cpp =================================================================== --- mythtv/libs/libmythtv/NuppelVideoRecorder.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/NuppelVideoRecorder.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -216,7 +216,10 @@ } if (mpa_codec) + { + QMutexLocker locker(&avcodeclock); avcodec_close(mpa_ctx); + } if (mpa_ctx) av_free(mpa_ctx); @@ -453,8 +456,11 @@ useavcodec = true; if (mpa_codec) + { + QMutexLocker locker(&avcodeclock); avcodec_close(mpa_ctx); - + } + if (mpa_ctx) av_free(mpa_ctx); mpa_ctx = NULL; @@ -626,13 +632,14 @@ int frag, blocksize = 4096; int tmp; + if (!skipdevice) + { #if !defined (HAVE_SYS_SOUNDCARD_H) && !defined(HAVE_SOUNDCARD_H) - VERBOSE(VB_IMPORTANT, QString("NVR::AudioInit() This Unix doesn't support" - " device files for audio access. Skipping")); - return 1; + VERBOSE(VB_IMPORTANT, + QString("NVR::AudioInit() This Unix doesn't support" + " device files for audio access. Skipping")); + return 1; #else - if (!skipdevice) - { if (-1 == (afd = open(audiodevice.ascii(), O_RDONLY | O_NONBLOCK))) { VERBOSE(VB_IMPORTANT, QString("NVR: Error, cannot open DSP '%1'"). @@ -678,8 +685,8 @@ } close(afd); +#endif } -#endif audio_bytes_per_sample = audio_channels * audio_bits / 8; blocksize *= 4; Index: mythtv/libs/libmythtv/signalmonitor.cpp =================================================================== --- mythtv/libs/libmythtv/signalmonitor.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/signalmonitor.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -100,9 +100,9 @@ uint wait_for_mask, const char *name) : QObject(NULL, name), channel(_channel), capturecardnum(_capturecardnum), flags(wait_for_mask), - update_rate(25), running(false), - exit(false), update_done(false), - notify_frontend(true), + update_rate(25), minimum_update_rate(5), + running(false), exit(false), + update_done(false), notify_frontend(true), signalLock (QObject::tr("Signal Lock"), "slock", 1, true, 0, 1, 0), signalStrength(QObject::tr("Signal Power"), "signal", Index: mythtv/libs/libmythtv/osdlistbtntype.cpp =================================================================== --- mythtv/libs/libmythtv/osdlistbtntype.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/osdlistbtntype.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -19,206 +19,148 @@ * * ============================================================ */ -#include +// ANSI C headers +#include +// C++ headers +#include +using namespace std; + +// Qt headers #include #include #include #include #include +// MythTV headers #include "mythcontext.h" #include "mythdialogs.h" - #include "osdlistbtntype.h" +#define LOC QString("OSDListTreeType: ") +#define LOC_ERR QString("OSDListTreeType, Error: ") -OSDGenericTree::OSDGenericTree(OSDGenericTree *parent, const QString &name, - const QString &action, int check, - OSDTypeImage *image, QString group) - : GenericTree(name) +static QRect unbias(QRect rect, float wmult, float hmult) { - m_checkable = check; - m_action = action; - m_image = image; - m_parentButton = NULL; - - if (group != "") - m_group = group; - else - m_group = action; - - if (!action.isEmpty() && !action.isNull()) - setSelectable(true); - - if (parent) - parent->addNode(this); + return QRect((int)round(rect.x() / wmult), + (int)round(rect.y() / hmult), + (int)ceil( rect.width() / wmult), + (int)ceil( rect.height() / hmult)); } -//////////////////////////////////////////////////////////////////////////// - -OSDListTreeType::OSDListTreeType(const QString &name, const QRect &area, - const QRect &levelsize, int levelspacing, - float wmult, float hmult) - : OSDType(name) +static QRect bias(QRect rect, float wmult, float hmult) { - m_wmult = wmult; - m_hmult = hmult; - - m_totalarea = area; - m_levelsize = levelsize; - m_levelspacing = levelspacing; - - if (gContext->GetNumSetting("UseArrowAccels", 1)) - m_arrowAccel = true; - else - m_arrowAccel = false; - - levels = 0; - curlevel = -1; - - treetop = NULL; - currentpos = NULL; - - currentlevel = NULL; - - listLevels.setAutoDelete(true); - - m_active = NULL; - m_inactive = NULL; - - SetItemRegColor(Qt::black,QColor(80,80,80),100); - SetItemSelColor(QColor(82,202,56),QColor(52,152,56),255); - - m_spacing = 0; - m_margin = 0; + return QRect((int)round(rect.x() * wmult), + (int)round(rect.y() * hmult), + (int)ceil( rect.width() * wmult), + (int)ceil( rect.height() * hmult)); } -void OSDListTreeType::Reinit(float wchange, float hchange, float wmult, - float hmult) +OSDListTreeType::OSDListTreeType( + const QString &name, const QRect &area, + const QRect &levelsize, int levelspacing, + float wmult, float hmult) + : OSDType(name), + treetop(NULL), currentpos(NULL), + m_active(NULL), m_inactive(NULL), + m_itemRegBeg(Qt::black), m_itemRegEnd(QColor(80,80,80)), + m_itemSelBeg(QColor(82,202,56)), m_itemSelEnd(QColor(52,152,56)), + m_itemRegAlpha(100), m_itemSelAlpha(255), + m_spacing(0), m_margin(0), + m_levelspacing(levelspacing), + m_totalarea(area), m_levelsize(levelsize), + m_unbiasedspacing(1.0f), m_unbiasedmargin(1.0f), + m_unbiasedarea(0,0,0,0), m_unbiasedsize(0,0,0,0), + m_wmult(wmult), m_hmult(hmult), + m_depth(0), m_levelnum(-1), + m_visible(true), + m_arrowAccel(gContext->GetNumSetting("UseArrowAccels", 1)) { - m_wmult = wmult; - m_hmult = hmult; - - m_spacing = (int)(m_spacing * wchange); - m_margin = (int)(m_margin * wchange); - - int width = (int)(m_totalarea.width() * wchange); - int height = (int)(m_totalarea.height() * hchange); - int x = (int)(m_totalarea.x() * wchange); - int y = (int)(m_totalarea.y() * hchange); - - m_totalarea = QRect(x, y, width, height); - - width = (int)(m_levelsize.width() * wchange); - height = (int)(m_levelsize.height() * hchange); - x = (int)(m_levelsize.x() * wchange); - y = (int)(m_levelsize.y() * hchange); - - m_levelsize = QRect(x, y, width, height); - - QPtrListIterator it(listLevels); - OSDListBtnType *child; - - while ((child = it.current()) != 0) - { - child->Reinit(wchange, hchange, wmult, hmult); - ++it; - } + m_wmult = (wmult == 0.0f) ? 1.0f : wmult; + m_hmult = (hmult == 0.0f) ? 1.0f : hmult; + m_unbiasedarea = unbias(area, wmult, hmult); + m_unbiasedsize = unbias(levelsize, wmult, hmult); } -void OSDListTreeType::SetGroupCheckState(QString group, int newState) +OSDListTreeType::~OSDListTreeType() { - QPtrListIterator it(listLevels); - OSDListBtnType *child; - while ((child = it.current()) != 0) - { - child->SetGroupCheckState(group, newState); - ++it; - } + OSDListBtnList::iterator it = listLevels.begin(); + for (; it != listLevels.end(); ++it) + delete *it; } -void OSDListTreeType::SetItemRegColor(const QColor& beg, const QColor& end, - uint alpha) +void OSDListTreeType::Reinit(float wmult, float hmult) { - m_itemRegBeg = beg; - m_itemRegEnd = end; - m_itemRegAlpha = alpha; -} + m_wmult = (wmult == 0.0f) ? 1.0f : wmult; + m_hmult = (hmult == 0.0f) ? 1.0f : hmult; + m_spacing = (uint) round(m_unbiasedspacing * wmult); + m_margin = (uint) round(m_unbiasedmargin * wmult); + m_totalarea = bias(m_unbiasedarea, wmult, hmult); + m_levelsize = bias(m_unbiasedsize, wmult, hmult); -void OSDListTreeType::SetItemSelColor(const QColor& beg, const QColor& end, - uint alpha) -{ - m_itemSelBeg = beg; - m_itemSelEnd = end; - m_itemSelAlpha = alpha; -} + if (!treetop || m_levelnum < 0) + return; -void OSDListTreeType::SetFontActive(TTFFont *font) -{ - m_active = font; -} + // Save item indices + vector list; + for (uint i = 0; i <= (uint)m_levelnum; i++) + list.push_back(listLevels[i]->GetItemCurrentPos()); -void OSDListTreeType::SetFontInactive(TTFFont *font) -{ - m_inactive = font; -} + // Delete old OSD items + OSDListBtnList clone = listLevels; + listLevels.clear(); + OSDListBtnList::iterator it = clone.begin(); + for (; it != clone.end(); ++it) + delete *it; -void OSDListTreeType::SetSpacing(int spacing) -{ - m_spacing = spacing; + // Create new OSD items + SetAsTree(treetop, &list); } -void OSDListTreeType::SetMargin(int margin) +void OSDListTreeType::SetGroupCheckState(QString group, int newState) { - m_margin = margin; + OSDListBtnList::iterator it = listLevels.begin(); + for (; it != listLevels.end(); ++it) + (*it)->SetGroupCheckState(group, newState); } -void OSDListTreeType::SetAsTree(OSDGenericTree *toplevel) +void OSDListTreeType::SetAsTree(OSDGenericTree *toplevel, + vector *select_list) { if (treetop) { listLevels.clear(); - currentlevel = NULL; - treetop = NULL; - currentpos = NULL; - levels = 0; - curlevel = -1; + treetop = NULL; + currentpos = NULL; + m_depth = 0; + m_levelnum = -1; } - levels = toplevel->calculateDepth(0) - 1; - - if (levels <= 0) + m_depth = toplevel->calculateDepth(0) - 1; + if (m_depth <= 0) { - cerr << "Need at least one level\n"; + VERBOSE(VB_IMPORTANT, LOC_ERR + "SetAsTree: Need at least one level"); return; } - currentpos = (OSDGenericTree *)toplevel->getChildAt(0); - + currentpos = (OSDGenericTree*) toplevel->getChildAt(0); if (!currentpos) { - cerr << "No top-level children?\n"; + VERBOSE(VB_IMPORTANT, LOC_ERR + "SetAsTree: Need top-level children"); return; } - treetop = toplevel; - - // just for now, remove later - if (levels > 2) - levels = 3; - - for (int i = 0; i < levels; i++) + // Create OSD buttons for all levels + for (uint i = 0; i < (uint)m_depth; i++) { QString levelname = QString("level%1").arg(i + 1); - QRect curlevelarea = m_levelsize; curlevelarea.moveBy(m_totalarea.x(), m_totalarea.y()); - curlevelarea.moveBy((m_levelsize.width() + m_levelspacing) * i, 0); - OSDListBtnType *newlevel = new OSDListBtnType(levelname, curlevelarea, - m_wmult, m_hmult, true); + OSDListBtnType *newlevel = new OSDListBtnType( + levelname, curlevelarea, m_wmult, m_hmult, true); newlevel->SetFontActive(m_active); newlevel->SetFontInactive(m_inactive); @@ -227,229 +169,200 @@ newlevel->SetSpacing(m_spacing); newlevel->SetMargin(m_margin); - listLevels.append(newlevel); + listLevels.push_back(newlevel); } - currentlevel = GetLevel(0); + // Set up needed levels and selects + vector slist; + slist.push_back(0); + if (select_list) + slist = *select_list; - if (!currentlevel) + currentpos = treetop = toplevel; + for (m_levelnum = 0; m_levelnum < (int)slist.size(); m_levelnum++) { - cerr << "Something is seriously wrong (currentlevel = NULL)\n"; - return; + FillLevelFromTree(currentpos, m_levelnum); + GetLevel(m_levelnum)->SetActive(true); + GetLevel(m_levelnum)->SetVisible(true); + if (slist[m_levelnum]) + GetLevel(m_levelnum)->SetItemCurrent(slist[m_levelnum]); + EnterItem(); // updates currentpos } - - FillLevelFromTree(toplevel, currentlevel); - - currentlevel->SetVisible(true); - currentlevel->SetActive(true); - - currentpos = (OSDGenericTree *)(currentlevel->GetItemFirst()->getData()); - curlevel = 0; - - emit itemEntered(this, currentpos); + m_levelnum--; } -OSDGenericTree *OSDListTreeType::GetCurrentPosition(void) +static bool has_action(QString action, const QStringList &actions) { - return currentpos; + QStringList::const_iterator it; + for (it = actions.begin(); it != actions.end(); ++it) + { + if (action == *it) + return true; + } + return false; } bool OSDListTreeType::HandleKeypress(QKeyEvent *e) { - if (!currentlevel) + QStringList actions; + bool ok = gContext->GetMainWindow()->TranslateKeyPress( + "TV Playback", e, actions); + + if (!ok || ((uint)m_levelnum >= listLevels.size())) return false; + else if (has_action("UP", actions)) + { + GetLevel(m_levelnum)->MoveUp(); + EnterItem(); + } + else if (has_action("DOWN", actions)) + { + GetLevel(m_levelnum)->MoveDown(); + EnterItem(); + } + else if (has_action("LEFT", actions) && (m_levelnum > 0)) + { + GetLevel(m_levelnum)->Reset(); + GetLevel(m_levelnum)->SetVisible(false); - bool handled = false; - QStringList actions; - if (gContext->GetMainWindow()->TranslateKeyPress("TV Playback", e, - actions)) + m_levelnum--; + EnterItem(); + } + else if ((has_action("LEFT", actions) && m_arrowAccel) || + has_action("ESCAPE", actions) || + has_action("CLEAROSD", actions) || + has_action("MENU", actions)) { - for (unsigned int i = 0; i < actions.size() && !handled; i++) - { - QString action = actions[i]; - handled = true; + m_visible = false; + } + else if (has_action("RIGHT", actions) && + (m_levelnum + 1 < m_depth) && + (currentpos->childCount() > 0)) + { + GetLevel(m_levelnum)->SetActive(false); + m_levelnum++; - if (action == "UP") - { - currentlevel->MoveUp(); - SetCurrentPosition(); - } - else if (action == "DOWN") - { - currentlevel->MoveDown(); - SetCurrentPosition(); - } - else if (action == "LEFT") - { - if (curlevel > 0) - { - currentlevel->Reset(); - currentlevel->SetVisible(false); - - curlevel--; - - currentlevel = GetLevel(curlevel); - currentlevel->SetActive(true); - SetCurrentPosition(); - } - else if (m_arrowAccel) - { - m_visible = false; - } - } - else if (action == "RIGHT") - { - // FIXME: create new levels if needed.. - if (curlevel + 1 < levels && currentpos->childCount() > 0) - { - currentlevel->SetActive(false); - - curlevel++; - - currentlevel = GetLevel(curlevel); - - FillLevelFromTree(currentpos, currentlevel); - - currentlevel->SetVisible(true); - currentlevel->SetActive(true); - SetCurrentPosition(); - } - else if (m_arrowAccel) - { - SetGroupCheckState(currentpos->getGroup(), - OSDListBtnTypeItem::NotChecked); - currentpos->getParentButton()->setChecked( - OSDListBtnTypeItem::FullChecked); - emit itemSelected(this, currentpos); - } - } - else if (action == "ESCAPE" || action == "MENU" || - action == "CLEAROSD") - m_visible = false; - else if (action == "SELECT") - { - SetGroupCheckState(currentpos->getGroup(), - OSDListBtnTypeItem::NotChecked); - currentpos->getParentButton()->setChecked( - OSDListBtnTypeItem::FullChecked); - emit itemSelected(this, currentpos); - } - else - handled = false; - } + FillLevelFromTree(currentpos, m_levelnum); + GetLevel(m_levelnum)->SetVisible(true); + EnterItem(); } + else if ((has_action("RIGHT", actions) && m_arrowAccel) || + has_action("SELECT", actions)) + { + SelectItem(); + } + else + { + return false; + } - return handled; + return true; } void OSDListTreeType::Draw(OSDSurface *surface, int fade, int maxfade, int xoff, int yoff) { - QPtrListIterator it(listLevels); - OSDListBtnType *child; - - while ((child = it.current()) != 0) - { - child->Draw(surface, fade, maxfade, xoff, yoff); - ++it; - } + OSDListBtnList::iterator it = listLevels.begin(); + for (; it != listLevels.end(); ++it) + (*it)->Draw(surface, fade, maxfade, xoff, yoff); } void OSDListTreeType::FillLevelFromTree(OSDGenericTree *item, - OSDListBtnType *list) + uint level_num) { + OSDListBtnType *list = GetLevel(level_num); if (!list) { - VERBOSE(VB_IMPORTANT, "OSDListTreeType::FillLevelFromTree() " - "called with no list. Ignoring call."); + VERBOSE(VB_IMPORTANT, LOC_ERR + "FillLevelFromTree() " + "called with no list, ignoring."); return; } list->Reset(); QPtrList *itemlist = item->getAllChildren(); - QPtrListIterator it(*itemlist); - GenericTree *child; - while ((child = it.current()) != 0) + OSDGenericTree *child = (OSDGenericTree*) it.current(); + OSDListBtnTypeItem *newitem = NULL; + for (;(child = (OSDGenericTree*) it.current()); ++it) { - OSDGenericTree *osdchild = (OSDGenericTree *)child; + OSDTypeImage *im = child->getImage(); + QString label = child->getString(); + QString group = child->getGroup(); + bool canCheck = child->getCheckable() >= 0; + bool hasCheck = child->getCheckable() == 1; + bool hasChild = child->childCount() > 0; - OSDListBtnTypeItem *newitem; - newitem = new OSDListBtnTypeItem(list, child->getString(), - osdchild->getImage(), - (osdchild->getCheckable() >= 0), - (child->childCount() > 0)); - if (osdchild->getCheckable() == 1) + newitem = new OSDListBtnTypeItem(list, label, im, canCheck, hasChild); + + if (hasCheck) newitem->setChecked(OSDListBtnTypeItem::FullChecked); - newitem->setGroup(osdchild->getGroup()); - newitem->setData(osdchild); - osdchild->setParentButton(newitem); + newitem->setGroup(group); + newitem->setData(child); - ++it; + child->setParentButton(newitem); } } -OSDListBtnType *OSDListTreeType::GetLevel(int levelnum) +OSDListBtnType *OSDListTreeType::GetLevel(uint levelnum) { - if ((uint)levelnum > listLevels.count()) - { - cerr << "OOB GetLevel call\n"; - return NULL; - } + if (levelnum < listLevels.size()) + return listLevels[levelnum]; - return listLevels.at(levelnum); + VERBOSE(VB_IMPORTANT, LOC_ERR + "GetLevel("<= listLevels.size()) return; - OSDListBtnTypeItem *lbt = currentlevel->GetItemCurrent(); + listLevels[m_levelnum]->SetActive(true); + OSDListBtnTypeItem *lbt = listLevels[m_levelnum]->GetItemCurrent(); + if (lbt) + { + currentpos = (OSDGenericTree*) (lbt->getData()); + emit itemEntered(this, currentpos); + } +} - if (!lbt) +void OSDListTreeType::SelectItem(void) +{ + if (!currentpos) return; - currentpos = (OSDGenericTree *)(lbt->getData()); - emit itemEntered(this, currentpos); + SetGroupCheckState(currentpos->getGroup(), OSDListBtnTypeItem::NotChecked); + currentpos->getParentButton()->setChecked(OSDListBtnTypeItem::FullChecked); + emit itemSelected(this, currentpos); } - + +#undef LOC_ERR +#undef LOC + ////////////////////////////////////////////////////////////////////////// OSDListBtnType::OSDListBtnType(const QString &name, const QRect &area, float wmult, float hmult, bool showScrollArrows) - : OSDType(name) + : OSDType(name), + m_order(0), m_rect(area), + m_contentsRect(0,0,0,0), m_arrowsRect(0,0,0,0), + m_wmult(wmult), m_hmult(hmult), + m_itemHeight(0), m_itemSpacing(0), + m_itemMargin(0), m_itemsVisible(0), + m_active(false), m_showScrollArrows(showScrollArrows), + m_showUpArrow(false), m_showDnArrow(false), + m_initialized(false), m_clearing(false), + m_visible(false), + m_itemRegBeg(Qt::black), m_itemRegEnd(QColor(80,80,80)), + m_itemSelBeg(QColor(82,202,56)), m_itemSelEnd(QColor(52,152,56)), + m_itemRegAlpha(100), m_itemSelAlpha(255), + m_fontActive(NULL), m_fontInactive(NULL), + m_topIndx(0), m_selIndx(0), + m_update(true) { - m_rect = area; - - m_wmult = wmult; - m_hmult = hmult; - - m_showScrollArrows = showScrollArrows; - - m_active = false; - m_showUpArrow = false; - m_showDnArrow = false; - - m_itemList.setAutoDelete(false); - m_topItem = 0; - m_selItem = 0; - - m_initialized = false; - m_clearing = false; - m_itemSpacing = 0; - m_itemMargin = 0; - m_itemHeight = 0; - m_itemsVisible = 0; - m_fontActive = 0; - m_fontInactive = 0; - - SetItemRegColor(Qt::black,QColor(80,80,80),100); - SetItemSelColor(QColor(82,202,56),QColor(52,152,56),255); - - m_visible = false; } OSDListBtnType::~OSDListBtnType() @@ -457,316 +370,198 @@ Reset(); } -void OSDListBtnType::Reinit(float wchange, float hchange, float wmult, - float hmult) -{ - m_wmult = wmult; - m_hmult = hmult; - - m_itemHeight = (int)(m_itemHeight * hchange); - m_itemSpacing = (int)(m_itemSpacing * wchange); - m_itemMargin = (int)(m_itemMargin * wchange); - - int width = (int)(m_rect.width() * wchange); - int height = (int)(m_rect.height() * hchange); - int x = (int)(m_rect.x() * wchange); - int y = (int)(m_rect.y() * hchange); - - m_rect = QRect(x, y, width, height); - - Init(); - - OSDListBtnTypeItem* item = 0; - for (item = m_itemList.first(); item; item = m_itemList.next()) { - item->Reinit(wchange, hchange, wmult, hmult); - } - -} - void OSDListBtnType::SetGroupCheckState(QString group, int newState) { - OSDListBtnTypeItem* item = 0; - for (item = m_itemList.first(); item; item = m_itemList.next()) { - if (item->getGroup() == group) - item->setChecked((OSDListBtnTypeItem::CheckState)newState); - } + OSDListBtnItemList::iterator it; + for (it = m_itemList.begin(); it != m_itemList.end(); ++it) + if ((*it)->getGroup() == group) + (*it)->setChecked((OSDListBtnTypeItem::CheckState) newState); } -void OSDListBtnType::SetItemRegColor(const QColor& beg, const QColor& end, - uint alpha) +void OSDListBtnType::Reset(void) { - m_itemRegBeg = beg; - m_itemRegEnd = end; - m_itemRegAlpha = alpha; -} - -void OSDListBtnType::SetItemSelColor(const QColor& beg, const QColor& end, - uint alpha) -{ - m_itemSelBeg = beg; - m_itemSelEnd = end; - m_itemSelAlpha = alpha; -} - -void OSDListBtnType::SetFontActive(TTFFont *font) -{ - m_fontActive = font; -} - -void OSDListBtnType::SetFontInactive(TTFFont *font) -{ - m_fontInactive = font; -} - -void OSDListBtnType::SetSpacing(int spacing) -{ - m_itemSpacing = spacing; -} - -void OSDListBtnType::SetMargin(int margin) -{ - m_itemMargin = margin; -} - -void OSDListBtnType::SetActive(bool active) -{ - m_active = active; -} - -void OSDListBtnType::Reset() -{ QMutexLocker lock(&m_update); m_clearing = true; - - OSDListBtnTypeItem* item = 0; - for (item = m_itemList.first(); item; item = m_itemList.next()) { - delete item; - } - - m_clearing = false; + OSDListBtnItemList::iterator it; + OSDListBtnItemList clone = m_itemList; m_itemList.clear(); - - m_topItem = 0; - m_selItem = 0; + for (it = clone.begin(); it != clone.end(); ++it) + delete (*it); + m_clearing = false; + + m_topIndx = 0; + m_selIndx = 0; m_showUpArrow = false; m_showDnArrow = false; } void OSDListBtnType::InsertItem(OSDListBtnTypeItem *item) { - OSDListBtnTypeItem* lastItem = m_itemList.last(); - m_itemList.append(item); - - if (m_showScrollArrows && m_itemList.count() > m_itemsVisible) - m_showDnArrow = true; - else - m_showDnArrow = false; - - if (!lastItem) - { - m_topItem = item; - m_selItem = item; + QMutexLocker lock(&m_update); + m_itemList.push_back(item); + m_showDnArrow = m_showScrollArrows && m_itemList.size() > m_itemsVisible; + if (m_itemList.size() == 1) emit itemSelected(item); - } } +int find(const OSDListBtnItemList &list, const OSDListBtnTypeItem *item) +{ + for (uint i = 0; i < list.size(); i++) + if (list[i] == item) + return i; + return -1; +} + void OSDListBtnType::RemoveItem(OSDListBtnTypeItem *item) { + QMutexLocker lock(&m_update); if (m_clearing) return; - - if (m_itemList.find(item) == -1) + + int i = find(m_itemList, item); + if (i < 0) return; - m_topItem = m_itemList.first(); - m_selItem = m_itemList.first(); + m_itemList.erase(m_itemList.begin()+i); - m_itemList.remove(item); - m_showUpArrow = false; - - if (m_showScrollArrows && m_itemList.count() > m_itemsVisible) - m_showDnArrow = true; - else - m_showDnArrow = false; + m_showDnArrow = m_itemList.size() > m_itemsVisible; + m_selIndx = 0; + m_topIndx = 0; - if (m_selItem) { - emit itemSelected(m_selItem); - } + if (m_itemList.size()) + emit itemSelected(m_itemList[m_selIndx]); } -void OSDListBtnType::SetItemCurrent(OSDListBtnTypeItem* item) +void OSDListBtnType::SetItemCurrent(const OSDListBtnTypeItem* item) { - bool locked = m_update.tryLock(); + QMutexLocker lock(&m_update); + int i = find(m_itemList, item); + if (i >= 0) + SetItemCurrent(i); +} - if (m_itemList.find(item) == -1) +void OSDListBtnType::SetItemCurrent(uint current) +{ + QMutexLocker lock(&m_update); + if (current >= m_itemList.size()) return; - m_topItem = item; - m_selItem = item; - - if (m_showScrollArrows && m_itemList.count() > m_itemsVisible) - m_showDnArrow = true; - else - m_showDnArrow = false; - - emit itemSelected(m_selItem); - - if (locked) - m_update.unlock(); + m_selIndx = current; + m_topIndx = max(m_selIndx - (int)m_itemsVisible, 0); + m_showUpArrow = m_topIndx; + m_showDnArrow = m_topIndx + m_itemsVisible < m_itemList.size(); + emit itemSelected(m_itemList[m_selIndx]); } -void OSDListBtnType::SetItemCurrent(int current) +int OSDListBtnType::GetItemCurrentPos(void) const { QMutexLocker lock(&m_update); - - OSDListBtnTypeItem* item = m_itemList.at(current); - if (!item) - item = m_itemList.first(); - - SetItemCurrent(item); + return (m_itemList.size()) ? m_selIndx : -1; } -OSDListBtnTypeItem* OSDListBtnType::GetItemCurrent() +OSDListBtnTypeItem* OSDListBtnType::GetItemCurrent(void) { - return m_selItem; + QMutexLocker lock(&m_update); + if (!m_itemList.size()) + return NULL; + return m_itemList[m_selIndx]; } -OSDListBtnTypeItem* OSDListBtnType::GetItemFirst() +OSDListBtnTypeItem* OSDListBtnType::GetItemFirst(void) { - return m_itemList.first(); + QMutexLocker lock(&m_update); + if (!m_itemList.size()) + return NULL; + return m_itemList[0]; } -OSDListBtnTypeItem* OSDListBtnType::GetItemNext(OSDListBtnTypeItem *item) +OSDListBtnTypeItem* OSDListBtnType::GetItemNext(const OSDListBtnTypeItem *item) { QMutexLocker lock(&m_update); - - if (m_itemList.find(item) == -1) - return 0; - - return m_itemList.next(); + int i = find(m_itemList, item) + 1; + if (i <= 0 || i >= (int)m_itemList.size()) + return NULL; + return m_itemList[i]; } -int OSDListBtnType::GetCount() +int OSDListBtnType::GetCount(void) const { - return m_itemList.count(); + QMutexLocker lock(&m_update); + return m_itemList.size(); } OSDListBtnTypeItem* OSDListBtnType::GetItemAt(int pos) { - return m_itemList.at(pos); + QMutexLocker lock(&m_update); + return m_itemList[pos]; } -int OSDListBtnType::GetItemPos(OSDListBtnTypeItem* item) +int OSDListBtnType::GetItemPos(const OSDListBtnTypeItem *item) const { QMutexLocker lock(&m_update); - - return m_itemList.find(item); + return find(m_itemList, item); } -void OSDListBtnType::MoveUp() +void OSDListBtnType::MoveUp(void) { QMutexLocker lock(&m_update); - - if (m_itemList.find(m_selItem) == -1) + if (!m_itemList.size()) return; - OSDListBtnTypeItem *item = m_itemList.prev(); - if (!item) + if (--m_selIndx < 0) { - item = m_itemList.last(); - if (!item) - return; - - if (m_itemList.count() > m_itemsVisible) - m_topItem = m_itemList.at(m_itemList.count() - m_itemsVisible); - else - m_topItem = m_itemList.first(); + m_selIndx = m_itemList.size() - 1; + m_topIndx = (m_itemList.size() > m_itemsVisible) ? + m_itemList.size() - m_itemsVisible : 0; } - m_selItem = item; + m_topIndx = (m_selIndx < m_topIndx) ? m_selIndx : m_topIndx; + m_showUpArrow = m_topIndx; + m_showDnArrow = m_topIndx + m_itemsVisible < m_itemList.size(); - if (m_itemList.find(m_selItem) < m_itemList.find(m_topItem)) - m_topItem = m_selItem; - - if (m_topItem != m_itemList.first()) - m_showUpArrow = true; - else - m_showUpArrow = false; - - if (m_itemList.find(m_topItem) + m_itemsVisible < m_itemList.count()) - m_showDnArrow = true; - else - m_showDnArrow = false; - - emit itemSelected(m_selItem); + emit itemSelected(m_itemList[m_selIndx]); } -void OSDListBtnType::MoveDown() +void OSDListBtnType::MoveDown(void) { QMutexLocker lock(&m_update); - - if (m_itemList.find(m_selItem) == -1) + if (!m_itemList.size()) return; - OSDListBtnTypeItem *item = m_itemList.next(); - if (!item) - { - item = m_itemList.first(); - if (!item) - return; + if (++m_selIndx >= (int)m_itemList.size()) + m_selIndx = m_topIndx = 0; - m_topItem = item; - } - - m_selItem = item; - - if (m_itemList.find(m_topItem) + m_itemsVisible <= - (unsigned int)m_itemList.find(m_selItem)) - { - m_topItem = m_itemList.at(m_itemList.find(m_topItem) + 1); - } + bool scroll_down = m_topIndx + (int)m_itemsVisible <= m_selIndx; + m_topIndx = (scroll_down) ? m_topIndx + 1 : m_topIndx; + + m_showUpArrow = m_topIndx; + m_showDnArrow = m_topIndx + m_itemsVisible < m_itemList.size(); - if (m_topItem != m_itemList.first()) - m_showUpArrow = true; - else - m_showUpArrow = false; - - if (m_itemList.find(m_topItem) + m_itemsVisible < m_itemList.count()) - m_showDnArrow = true; - else - m_showDnArrow = false; - - emit itemSelected(m_selItem); + emit itemSelected(m_itemList[m_selIndx]); } -void OSDListBtnType::Draw(OSDSurface *surface, int fade, int maxfade, int xoff, - int yoff) +void OSDListBtnType::Draw(OSDSurface *surface, + int fade, int maxfade, + int xoff, int yoff) { - (void)xoff; - (void)yoff; - + QMutexLocker lock(&m_update); if (!m_visible) return; - - QMutexLocker lock(&m_update); - if (!m_initialized) Init(); TTFFont *font = m_active ? m_fontActive : m_fontInactive; int y = m_rect.y(); - m_itemList.find(m_topItem); - OSDListBtnTypeItem *it = m_itemList.current(); - while (it && (y - m_rect.y()) <= (m_contentsRect.height() - m_itemHeight)) + for (uint i = m_topIndx; i < m_itemList.size(); i++) { - it->paint(surface, font, fade, maxfade, m_rect.x()+ xoff, y + yoff); - + if (!((y - m_rect.y()) <= (m_contentsRect.height() - m_itemHeight))) + break; + m_itemList[i]->paint(surface, font, fade, maxfade, + m_rect.x() + xoff, y + yoff); y += m_itemHeight + m_itemSpacing; - - it = m_itemList.next(); } if (m_showScrollArrows) @@ -792,14 +587,13 @@ } } -void OSDListBtnType::Init() +void OSDListBtnType::Init(void) { int sz1 = m_fontActive->Size() * 3 / 2; int sz2 = m_fontInactive->Size() * 3 / 2; - m_itemHeight = QMAX(sz1, sz2) + (int)(2 * m_itemMargin); + m_itemHeight = max(sz1, sz2) + (int)(2 * m_itemMargin); + m_itemHeight = m_itemHeight & ~0x1; - m_itemHeight = (m_itemHeight / 2) * 2; - if (m_showScrollArrows) { LoadPixmap(m_upArrowRegPix, "uparrow-reg"); @@ -838,11 +632,7 @@ InitItem(m_itemSelActPix, itemWidth, m_itemHeight, m_itemSelBeg, m_itemSelEnd, 255); - if (m_itemList.count() > m_itemsVisible && m_showScrollArrows) - m_showDnArrow = true; - else - m_showDnArrow = false; - + m_showDnArrow = m_itemList.size() > m_itemsVisible && m_showScrollArrows; m_initialized = true; } @@ -885,68 +675,57 @@ void OSDListBtnType::LoadPixmap(OSDTypeImage& pix, const QString& fileName) { - QString file = gContext->GetThemesParentDir() + "default/lb-" + fileName + ".png"; - pix.LoadImage(file, m_wmult, m_hmult); + QString path = gContext->GetThemesParentDir() + "default/lb-"; + pix.LoadImage(path + fileName + ".png", m_wmult, m_hmult); } ///////////////////////////////////////////////////////////////////////////// -OSDListBtnTypeItem::OSDListBtnTypeItem(OSDListBtnType* lbtype, - const QString& text, - OSDTypeImage *pixmap, bool checkable, - bool showArrow, CheckState state) +OSDListBtnTypeItem::OSDListBtnTypeItem( + OSDListBtnType *lbtype, const QString &text, + OSDTypeImage *pixmap, bool checkable, + bool showArrow, CheckState state) + : m_parent(lbtype), m_pixmap(pixmap), + m_data(NULL), m_text(text), + m_group(QString::null), m_state(state), + m_showArrow(showArrow), m_checkable(checkable), + m_checkRect(0,0,0,0), m_arrowRect(0,0,0,0), + m_pixmapRect(0,0,0,0), m_textRect(0,0,0,0) { - m_parent = lbtype; - m_text = text; - m_pixmap = pixmap; - m_checkable = checkable; - m_state = state; - m_showArrow = showArrow; - m_data = 0; - if (!m_parent->m_initialized) m_parent->Init(); - int margin = m_parent->m_itemMargin; - int width = m_parent->m_rect.width(); - int height = m_parent->m_itemHeight; + OSDTypeImage &checkPix = m_parent->m_checkNonePix; + OSDTypeImage &arrowPix = m_parent->m_arrowPix; - OSDTypeImage& checkPix = m_parent->m_checkNonePix; - OSDTypeImage& arrowPix = m_parent->m_arrowPix; - - int cw = checkPix.ImageSize().width(); - int ch = checkPix.ImageSize().height(); - int aw = arrowPix.ImageSize().width(); - int ah = arrowPix.ImageSize().height(); - int pw = m_pixmap ? m_pixmap->ImageSize().width() : 0; - int ph = m_pixmap ? m_pixmap->ImageSize().height() : 0; - + int margin = m_parent->m_itemMargin; + int width = m_parent->m_rect.width(); + int height = m_parent->m_itemHeight; + int cw = checkPix.ImageSize().width(); + int ch = checkPix.ImageSize().height(); + int aw = arrowPix.ImageSize().width(); + int ah = arrowPix.ImageSize().height(); + int pw = m_pixmap ? m_pixmap->ImageSize().width() : 0; + int ph = m_pixmap ? m_pixmap->ImageSize().height() : 0; + if (m_checkable) - m_checkRect = QRect(margin, (height - ch)/2, cw, ch); - else - m_checkRect = QRect(0,0,0,0); + m_checkRect = QRect(margin, (height - ch)/2, cw, ch); if (m_showArrow) - m_arrowRect = QRect(width - aw - margin, (height - ah)/2, - aw, ah); - else - m_arrowRect = QRect(0,0,0,0); + m_arrowRect = QRect(width - aw - margin, (height - ah)/2, aw, ah); - if (m_pixmap) - m_pixmapRect = QRect(m_checkable ? (2*margin + m_checkRect.width()) : - margin, (height - ph)/2, - pw, ph); - else - m_pixmapRect = QRect(0,0,0,0); + if (m_pixmap) + { + int tmp = (m_checkable) ? (2 * margin + m_checkRect.width()) : margin; + m_pixmapRect = QRect(tmp, (height - ph)/2, pw, ph); + } - m_textRect = QRect(margin + - (m_checkable ? m_checkRect.width() + margin : 0) + - (m_pixmap ? m_pixmapRect.width() + margin : 0), - 0, - width - 2*margin - - (m_checkable ? m_checkRect.width() + margin : 0) - - (m_showArrow ? m_arrowRect.width() + margin : 0) - - (m_pixmap ? m_pixmapRect.width() + margin : 0), - height); + int tx = margin, tw = width - (2 * margin); + tx += (m_checkable) ? m_checkRect.width() + margin : 0; + tx += (m_pixmap) ? m_pixmapRect.width() + margin : 0; + tw -= (m_checkable) ? m_checkRect.width() + margin : 0; + tw -= (m_showArrow) ? m_arrowRect.width() + margin : 0; + tw -= (m_pixmap) ? m_pixmapRect.width() + margin : 0; + m_textRect = QRect(tx, 0, tw, height); m_parent->InsertItem(this); } @@ -957,52 +736,10 @@ m_parent->RemoveItem(this); } -QString OSDListBtnTypeItem::text() const -{ - return m_text; -} - -const OSDTypeImage* OSDListBtnTypeItem::pixmap() const -{ - return m_pixmap; -} - -bool OSDListBtnTypeItem::checkable() const -{ - return m_checkable; -} - -OSDListBtnTypeItem::CheckState OSDListBtnTypeItem::state() const -{ - return m_state; -} - -OSDListBtnType* OSDListBtnTypeItem::parent() const -{ - return m_parent; -} - -void OSDListBtnTypeItem::setChecked(CheckState state) -{ - if (!m_checkable) - return; - m_state = state; -} - -void OSDListBtnTypeItem::setData(void *data) -{ - m_data = data; -} - -void* OSDListBtnTypeItem::getData() -{ - return m_data; -} - void OSDListBtnTypeItem::paint(OSDSurface *surface, TTFFont *font, int fade, int maxfade, int x, int y) { - if (this == m_parent->m_selItem) + if (this == m_parent->GetItemCurrent()) { if (m_parent->m_active) m_parent->m_itemSelActPix.Draw(surface, fade, maxfade, x, y); @@ -1030,11 +767,14 @@ cr.moveBy(x, y); if (m_state == HalfChecked) - m_parent->m_checkHalfPix.Draw(surface, fade, maxfade, cr.x(), cr.y()); + m_parent->m_checkHalfPix.Draw(surface, fade, maxfade, + cr.x(), cr.y()); else if (m_state == FullChecked) - m_parent->m_checkFullPix.Draw(surface, fade, maxfade, cr.x(), cr.y()); + m_parent->m_checkFullPix.Draw(surface, fade, maxfade, + cr.x(), cr.y()); else - m_parent->m_checkNonePix.Draw(surface, fade, maxfade, cr.x(), cr.y()); + m_parent->m_checkNonePix.Draw(surface, fade, maxfade, + cr.x(), cr.y()); } if (m_pixmap) @@ -1049,39 +789,3 @@ tr.moveBy(0, font->Size() / 4); font->DrawString(surface, tr.x(), tr.y(), m_text, tr.right(), tr.bottom()); } - -void OSDListBtnTypeItem::Reinit(float wchange, float hchange, - float wmult, float hmult) -{ - (void)wmult; - (void)hmult; - - int width = (int)(m_checkRect.width() * wchange); - int height = (int)(m_checkRect.height() * hchange); - int x = (int)(m_checkRect.x() * wchange); - int y = (int)(m_checkRect.y() * hchange); - - m_checkRect = QRect(x, y, width, height); - - width = (int)(m_pixmapRect.width() * wchange); - height = (int)(m_pixmapRect.height() * hchange); - x = (int)(m_pixmapRect.x() * wchange); - y = (int)(m_pixmapRect.y() * hchange); - - m_pixmapRect = QRect(x, y, width, height); - - width = (int)(m_textRect.width() * wchange); - height = (int)(m_textRect.height() * hchange); - x = (int)(m_textRect.x() * wchange); - y = (int)(m_textRect.y() * hchange); - - m_textRect = QRect(x, y, width, height); - - width = (int)(m_arrowRect.width() * wchange); - height = (int)(m_arrowRect.height() * hchange); - x = (int)(m_arrowRect.x() * wchange); - y = (int)(m_arrowRect.y() * hchange); - - m_arrowRect = QRect(x, y, width, height); -} - Index: mythtv/libs/libmythtv/RingBuffer.cpp =================================================================== --- mythtv/libs/libmythtv/RingBuffer.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/RingBuffer.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -145,6 +145,12 @@ VERBOSE(VB_PLAYBACK, LOC + QString("OpenFile(%1, %1)") .arg(lfilename).arg(retryCount)); + if ((filename.right(4).lower() == ".png") || + (filename.right(4).lower() == ".gif")) + { + retryCount = 0; + } + uint openAttempts = retryCount + 1; filename = lfilename; @@ -162,6 +168,7 @@ bool is_local = false; bool is_dvd = false; + if ((filename.left(7) == "myth://") && (filename.length() > 7 )) { @@ -271,6 +278,11 @@ remotefile = NULL; } } + + setswitchtonext = false; + ateof = false; + commserror = false; + numfailures = 0; } /** \fn RingBuffer::IsOpen(void) const @@ -727,7 +739,7 @@ loops = 0; pthread_rwlock_rdlock(&rwlock); - if (totfree > readblocksize && !commserror) + if (totfree > readblocksize && !commserror && !ateof && !setswitchtonext) { // limit the read size totfree = readblocksize; @@ -737,6 +749,9 @@ if (remotefile) { + if (livetvchain && livetvchain->HasNext()) + remotefile->SetTimeout(true); + ret = safe_read(remotefile, readAheadBuffer + rbwpos, totfree); internalreadpos += ret; @@ -785,8 +800,16 @@ totfree = 0; } - if (!readsallowed && used >= fill_min) + if (!readsallowed && (used >= fill_min || setswitchtonext)) + { readsallowed = true; + VERBOSE(VB_PLAYBACK, QString("reads allowed (%1 %2)").arg(used) + .arg(fill_min)); + } + else if (!readsallowed) + VERBOSE(VB_PLAYBACK, QString("buffering (%1 %2 %3)").arg(used) + .arg(fill_min) + .arg(ret)); if (readsallowed && used < fill_min && !ateof && !setswitchtonext) { @@ -808,8 +831,11 @@ pthread_rwlock_unlock(&rwlock); - if ((used >= fill_threshold || wantseek) && !pausereadthread) + if ((used >= fill_threshold || wantseek || ateof || setswitchtonext) && + !pausereadthread) + { usleep(500); + } } delete [] readAheadBuffer; @@ -853,15 +879,15 @@ VERBOSE(VB_IMPORTANT, LOC + "Taking too long to be allowed to read.."); readErr++; - + // HACK Sometimes the readhead thread gets borked on startup. - /* if ((readErr % 2) && (rbrpos ==0)) + if ((readErr > 2 && readErr % 2) && (rbrpos ==0)) { VERBOSE(VB_IMPORTANT, "restarting readhead thread.."); KillReadAheadThread(); StartupReadAheadThread(); } - */ + if (readErr > 10) { VERBOSE(VB_IMPORTANT, LOC_ERR + "Took more than " @@ -895,6 +921,12 @@ VERBOSE(VB_IMPORTANT, LOC + "Waited " + QString("%1").arg(elapsed/1000) + " seconds for data to become available..."); + if (livetvchain) + { + VERBOSE(VB_IMPORTANT, "Checking to see if there's a " + "new livetv program to switch to.."); + livetvchain->ReloadAll(); + } } bool quit = livetvchain && (livetvchain->NeedsToSwitch() || @@ -923,7 +955,7 @@ availWaitMutex.unlock(); avail = ReadBufAvail(); - if (ateof && avail < count) + if ((ateof || setswitchtonext) && avail < count) count = avail; if (commserror) Index: mythtv/libs/libmythtv/hdtvrecorder.cpp =================================================================== --- mythtv/libs/libmythtv/hdtvrecorder.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/hdtvrecorder.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -627,9 +627,8 @@ len += remainder; remainder = ProcessData(_buffer, len); - if (remainder > 0) // leftover bytes - memmove(_buffer, &(_buffer[_buffer_size - remainder]), - remainder); + if (remainder > 0 && (len > remainder)) // leftover bytes + memmove(_buffer, &(_buffer[len - remainder]), remainder); } FinishRecording(); Index: mythtv/libs/libmythtv/dummydtvrecorder.cpp =================================================================== --- mythtv/libs/libmythtv/dummydtvrecorder.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/dummydtvrecorder.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -125,7 +125,8 @@ // TRANSFER DATA while (_request_recording || _frames_seen_count <= 5) { - len = read(_stream_fd, &(_buffer[remainder]), _buffer_size - remainder); + len = read(_stream_fd, &(_buffer[remainder]), + _buffer_size - remainder); if (len == 0) { @@ -137,9 +138,8 @@ len += remainder; remainder = ProcessData(_buffer, len); - if (remainder > 0) // leftover bytes - memmove(_buffer, &(_buffer[_buffer_size - remainder]), - remainder); + if (remainder > 0 && (len > remainder)) // leftover bytes + memmove(_buffer, &(_buffer[len - remainder]), remainder); } FinishRecording(); Index: mythtv/libs/libmythtv/avformatdecoder.cpp =================================================================== --- mythtv/libs/libmythtv/avformatdecoder.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/avformatdecoder.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -725,7 +725,12 @@ return -1; } + /* av_find_stream_info() eventually makes calls to avcodec_open() and avcodec_close() + so we have to use the avcodeclock */ + avcodeclock.lock(); int ret = av_find_stream_info(ic); + avcodeclock.unlock(); + if (ret < 0) { VERBOSE(VB_IMPORTANT, LOC_ERR + "Could not find codec parameters. " + Index: mythtv/libs/libmythtv/osdtypes.cpp =================================================================== --- mythtv/libs/libmythtv/osdtypes.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/osdtypes.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -14,6 +14,9 @@ #include "mythcontext.h" +/// Shared OSD image cache +OSDImageCache OSDTypeImage::c_cache; + OSDSet::OSDSet(const QString &name, bool cache, int screenwidth, int screenheight, float wmult, float hmult, int frint) : QObject() @@ -160,9 +163,6 @@ int displaywidth, int displayheight, float wmult, float hmult, int frint) { - float wchange = wmult / m_wmult; - float hchange = hmult / m_hmult; - m_frameint = frint; m_screenwidth = screenwidth; @@ -175,57 +175,12 @@ vector::iterator iter = allTypes->begin(); for (;iter != allTypes->end(); iter++) { - OSDType *type = (*iter); - if (OSDTypeText *item = dynamic_cast(type)) - { - item->Reinit(wchange, hchange); - } - else if (OSDTypePositionImage *item = - dynamic_cast(type)) - { - item->Reinit(wchange, hchange, wmult, hmult); - } - else if (OSDTypePosSlider *item = dynamic_cast(type)) - { - item->Reinit(wchange, hchange, wmult, hmult); - } - else if (OSDTypeFillSlider *item = - dynamic_cast(type)) - { - item->Reinit(wchange, hchange, wmult, hmult); - } - else if (OSDTypeEditSlider *item = - dynamic_cast(type)) - { - item->Reinit(wchange, hchange, wmult, hmult); - } - else if (OSDTypeImage *item = dynamic_cast(type)) - { - item->Reinit(wchange, hchange, wmult, hmult); - } - else if (OSDTypeBox *item = dynamic_cast(type)) - { - item->Reinit(wchange, hchange); - } - else if (OSDTypePositionRectangle *item = - dynamic_cast(type)) - { - item->Reinit(wchange, hchange); - } - else if (OSDTypeCC *item = dynamic_cast(type)) - { - item->Reinit(xoff, yoff, displaywidth, displayheight); - } - else if (OSDListTreeType *item = dynamic_cast(type)) - { - item->Reinit(wchange, hchange, wmult, hmult); - } + if (OSDTypeCC *cc608 = dynamic_cast(*iter)) + cc608->Reinit(xoff, yoff, displaywidth, displayheight, + wmult, hmult); else - { - cerr << "Unknown conversion\n"; - } + (*iter)->Reinit(wmult, hmult); } - } OSDType *OSDSet::GetType(const QString &name) @@ -443,7 +398,8 @@ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OSDTypeText::OSDTypeText(const QString &name, TTFFont *font, - const QString &text, QRect displayrect) + const QString &text, QRect displayrect, + float wmult, float hmult) : OSDType(name) { m_message = text; @@ -464,6 +420,12 @@ m_scrollinit = false; m_linespacing = 1.5; + + m_unbiasedsize = + QRect((int)round(m_screensize.x() / wmult), + (int)round(m_screensize.y() / hmult), + (int)ceil( m_screensize.width() / wmult), + (int)ceil( m_screensize.height() / hmult)); } OSDTypeText::OSDTypeText(const OSDTypeText &other) @@ -507,14 +469,13 @@ m_scrollinit = false; } -void OSDTypeText::Reinit(float wchange, float hchange) +void OSDTypeText::Reinit(float wmult, float hmult) { - int width = (int)(m_screensize.width() * wchange); - int height = (int)(m_screensize.height() * hchange); - int x = (int)(m_screensize.x() * wchange); - int y = (int)(m_screensize.y() * hchange); - - m_displaysize = m_screensize = QRect(x, y, width, height); + m_displaysize = m_screensize = + QRect((int)round(m_unbiasedsize.x() * wmult), + (int)round(m_unbiasedsize.y() * hmult), + (int)ceil( m_unbiasedsize.width() * wmult), + (int)ceil( m_unbiasedsize.height() * hmult)); } void OSDTypeText::Draw(OSDSurface *surface, int fade, int maxfade, int xoff, @@ -708,7 +669,7 @@ m_onlyusefirst = false; m_filename = filename; - m_displaypos = displaypos; + SetPosition(displaypos, wmult, hmult); m_yuv = m_alpha = NULL; m_isvalid = false; @@ -716,6 +677,7 @@ m_scalew = scalew; m_scaleh = scaleh; + m_cacheitem = NULL; LoadImage(filename, wmult, hmult, scalew, scaleh); } @@ -733,6 +695,7 @@ m_name = other.m_name; m_scalew = other.m_scalew; m_scaleh = other.m_scaleh; + m_cacheitem = NULL; m_alpha = m_yuv = NULL; if (m_isvalid) @@ -760,6 +723,8 @@ m_onlyusefirst = false; m_displaypos = QPoint(0, 0); + m_unbiasedpos = QPoint(0, 0); + m_cacheitem = NULL; m_yuv = NULL; m_alpha = NULL; @@ -778,6 +743,8 @@ m_onlyusefirst = false; m_displaypos = QPoint(0, 0); + m_unbiasedpos = QPoint(0, 0); + m_cacheitem = NULL; m_yuv = NULL; m_alpha = NULL; @@ -790,10 +757,14 @@ OSDTypeImage::~OSDTypeImage() { - if (m_yuv) - delete [] m_yuv; - if (m_alpha) - delete [] m_alpha; + // In case we have a cache item in hand, it's safe to delete it, + // as it should not be in OSDImageCache anymore and it should have + // been written to the file cache for faster access in the future. + if (m_cacheitem) + { + delete m_cacheitem; + m_cacheitem = NULL; + } } void OSDTypeImage::SetName(const QString &name) @@ -801,13 +772,19 @@ m_name = name; } -void OSDTypeImage::Reinit(float wchange, float hchange, float wmult, float hmult) +void OSDTypeImage::SetPosition(QPoint pos, float wmult, float hmult) { - int x = (int)(m_displaypos.x() * wchange); - int y = (int)(m_displaypos.y() * hchange); + m_displaypos = pos; + m_unbiasedpos = + QPoint((int)round(pos.x() / wmult), + (int)round(pos.y() / hmult)); +} - m_displaypos.setX(x); - m_displaypos.setY(y); +void OSDTypeImage::Reinit(float wmult, float hmult) +{ + m_displaypos = + QPoint((int)round(m_unbiasedpos.x() * wmult), + (int)round(m_unbiasedpos.y() * hmult)); LoadImage(m_filename, wmult, hmult, m_scalew, m_scaleh); } @@ -815,20 +792,44 @@ void OSDTypeImage::LoadImage(const QString &filename, float wmult, float hmult, int scalew, int scaleh) { - if (m_isvalid) + QString ckey; + + if (!filename.isEmpty() && filename.length() >= 2) { - if (m_yuv) - delete [] m_yuv; - if (m_alpha) - delete [] m_alpha; - - m_isvalid = false; - m_yuv = NULL; - m_alpha = NULL; + ckey = OSDImageCache::CreateKey( + filename, wmult, hmult, scalew, scaleh); } + else + { + // this method requires a backing file + return; + } + + // Get the item from the cache so it's not freed while in use + OSDImageCacheValue* value = c_cache.Get(ckey, true); + + if (value != NULL) + { + m_yuv = value->m_yuv; + m_ybuffer = value->m_ybuffer; + m_ubuffer = value->m_ubuffer; + m_vbuffer = value->m_vbuffer; + m_alpha = value->m_alpha; + m_imagesize = value->m_imagesize; + m_isvalid = true; - if (filename.length() < 2) + // Put the old image back to the cache so it can be reused in the + // future, and possibly freed by the cache system if the size limit + // is reached + if (!m_cacheitem) + c_cache.Insert(m_cacheitem); + m_cacheitem = value; + return; + } + + // scaled image was not found in cache, have to create it + QImage tmpimage(filename); @@ -867,17 +868,32 @@ imwidth, imheight, tmp2.width()); m_imagesize = QRect(0, 0, imwidth, imheight); + + // put the old image back to the cache so it can be reused in the + // future, and possibly freed by the cache system if the size limit + // is reached + if (m_cacheitem) + c_cache.Insert(m_cacheitem); + + m_cacheitem = new OSDImageCacheValue( + ckey, + m_yuv, m_ybuffer, m_ubuffer, + m_vbuffer, m_alpha, m_imagesize); + + // save the new cache item to the file cache + if (!filename.isEmpty()) + c_cache.SaveToDisk(m_cacheitem); } void OSDTypeImage::LoadFromQImage(const QImage &img) { + // this method is not cached as it's used mostly for + // subtitles which are displayed only once anyways, caching + // would probably only slow things down overall if (m_isvalid) { - if (m_yuv) - delete [] m_yuv; - if (m_alpha) - delete [] m_alpha; - + delete m_cacheitem; + m_cacheitem = NULL; m_isvalid = false; m_yuv = NULL; m_alpha = NULL; @@ -1043,23 +1059,25 @@ m_maxval = 1000; m_curval = 0; m_displayrect = displayrect; + m_unbiasedrect = + QRect((int)round(m_displayrect.x() / wmult), + (int)round(m_displayrect.y() / hmult), + (int)ceil( m_displayrect.width() / wmult), + (int)ceil( m_displayrect.height() / hmult)); } OSDTypePosSlider::~OSDTypePosSlider() { } -void OSDTypePosSlider::Reinit(float wchange, float hchange, float wmult, - float hmult) +void OSDTypePosSlider::Reinit(float wmult, float hmult) { - int width = (int)(m_displayrect.width() * wchange); - int height = (int)(m_displayrect.height() * hchange); - int x = (int)(m_displayrect.x() * wchange); - int y = (int)(m_displayrect.y() * hchange); - - m_displayrect = QRect(x, y, width, height); - - OSDTypeImage::Reinit(wchange, hchange, wmult, hmult); + m_displayrect = + QRect((int)round(m_unbiasedrect.x() * wmult), + (int)round(m_unbiasedrect.y() * hmult), + (int)ceil( m_unbiasedrect.width() * wmult), + (int)ceil( m_unbiasedrect.height() * hmult)); + OSDTypeImage::Reinit(wmult, hmult); } void OSDTypePosSlider::SetPosition(int pos) @@ -1092,23 +1110,25 @@ m_drawwidth = 0; m_onlyusefirst = true; m_displayrect = displayrect; + m_unbiasedrect = + QRect((int)round(m_displayrect.x() / wmult), + (int)round(m_displayrect.y() / hmult), + (int)ceil( m_displayrect.width() / wmult), + (int)ceil( m_displayrect.height() / hmult)); } OSDTypeFillSlider::~OSDTypeFillSlider() { } -void OSDTypeFillSlider::Reinit(float wchange, float hchange, float wmult, - float hmult) +void OSDTypeFillSlider::Reinit(float wmult, float hmult) { - int width = (int)(m_displayrect.width() * wchange); - int height = (int)(m_displayrect.height() * hchange); - int x = (int)(m_displayrect.x() * wchange); - int y = (int)(m_displayrect.y() * hchange); - - m_displayrect = QRect(x, y, width, height); - - OSDTypeImage::Reinit(wchange, hchange, wmult, hmult); + m_displayrect = + QRect((int)round(m_unbiasedrect.x() * wmult), + (int)round(m_unbiasedrect.y() * hmult), + (int)ceil( m_unbiasedrect.width() * wmult), + (int)ceil( m_unbiasedrect.height() * hmult)); + OSDTypeImage::Reinit(wmult, hmult); } void OSDTypeFillSlider::SetPosition(int pos) @@ -1143,6 +1163,11 @@ m_maxval = 1000; m_curval = 0; m_displayrect = displayrect; + m_unbiasedrect = + QRect((int)round(m_displayrect.x() / wmult), + (int)round(m_displayrect.y() / hmult), + (int)ceil( m_displayrect.width() / wmult), + (int)ceil( m_displayrect.height() / hmult)); m_drawwidth = displayrect.width(); m_drawMap = new unsigned char[m_drawwidth + 1]; @@ -1162,6 +1187,7 @@ m_scalew = scalew; m_scaleh = scaleh; + m_cacheitem = NULL; LoadImage(m_redname, wmult, hmult, scalew, scaleh); if (m_isvalid) @@ -1184,22 +1210,16 @@ OSDTypeEditSlider::~OSDTypeEditSlider() { delete [] m_drawMap; - - if (m_ryuv) - delete [] m_ryuv; - if (m_ralpha) - delete [] m_ralpha; } -void OSDTypeEditSlider::Reinit(float wchange, float hchange, float wmult, - float hmult) +void OSDTypeEditSlider::Reinit(float wmult, float hmult) { - int width = (int)(m_displayrect.width() * wchange); - int height = (int)(m_displayrect.height() * hchange); - int x = (int)(m_displayrect.x() * wchange); - int y = (int)(m_displayrect.y() * hchange); + m_displayrect = + QRect((int)round(m_unbiasedrect.x() * wmult), + (int)round(m_unbiasedrect.y() * hmult), + (int)ceil( m_unbiasedrect.width() * wmult), + (int)ceil( m_unbiasedrect.height() * hmult)); - m_displayrect = QRect(x, y, width, height); m_drawwidth = m_displayrect.width(); delete [] m_drawMap; @@ -1210,11 +1230,6 @@ m_displaypos = m_displayrect.topLeft(); - if (m_ryuv) - delete [] m_ryuv; - if (m_ralpha) - delete [] m_ralpha; - LoadImage(m_redname, wmult, hmult, m_scalew, m_scaleh); if (m_isvalid) { @@ -1360,30 +1375,46 @@ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -OSDTypeBox::OSDTypeBox(const QString &name, QRect displayrect) - : OSDType(name) +OSDTypeBox::OSDTypeBox(const QString &name, QRect displayrect, + float wmult, float hmult) + : OSDType(name) { size = displayrect; + m_unbiasedsize = + QRect((int)round(size.x() / wmult), + (int)round(size.y() / hmult), + (int)ceil( size.width() / wmult), + (int)ceil( size.height() / hmult)); } +void OSDTypeBox::SetRect(QRect newrect, float wmult, float hmult) +{ + size = newrect; + m_unbiasedsize = + QRect((int)round(size.x() / wmult), + (int)round(size.y() / hmult), + (int)ceil( size.width() / wmult), + (int)ceil( size.height() / hmult)); +} + OSDTypeBox::OSDTypeBox(const OSDTypeBox &other) : OSDType(other.m_name) { size = other.size; + m_unbiasedsize = other.m_unbiasedsize; } OSDTypeBox::~OSDTypeBox() { } -void OSDTypeBox::Reinit(float wchange, float hchange) +void OSDTypeBox::Reinit(float wmult, float hmult) { - int width = (int)(size.width() * wchange); - int height = (int)(size.height() * hchange); - int x = (int)(size.x() * wchange); - int y = (int)(size.y() * hchange); - - size = QRect(x, y, width, height); + size = + QRect((int)round(m_unbiasedsize.x() * wmult), + (int)round(m_unbiasedsize.y() * hmult), + (int)ceil( m_unbiasedsize.width() * wmult), + (int)ceil( m_unbiasedsize.height() * hmult)); } void OSDTypeBox::Draw(OSDSurface *surface, int fade, int maxfade, int xoff, @@ -1498,44 +1529,52 @@ } OSDTypePositionRectangle::OSDTypePositionRectangle( - const OSDTypePositionRectangle &other) - : OSDType(other.m_name), OSDTypePositionIndicator(other) + const OSDTypePositionRectangle &other) + : OSDType(other.m_name), OSDTypePositionIndicator(other) { for (int i = 0; i < m_numpositions; i++) { QRect tmp = other.positions[i]; positions.push_back(tmp); } + for (int i = 0; i < m_numpositions; i++) + { + QRect tmp = other.unbiasedpos[i]; + unbiasedpos.push_back(tmp); + } } OSDTypePositionRectangle::~OSDTypePositionRectangle() { } -void OSDTypePositionRectangle::Reinit(float wchange, float hchange) +void OSDTypePositionRectangle::Reinit(float wmult, float hmult) { for (int i = 0; i < m_numpositions; i++) { - QRect tmp = positions[i]; - - int width = (int)(tmp.width() * wchange); - int height = (int)(tmp.height() * hchange); - int x = (int)(tmp.x() * wchange); - int y = (int)(tmp.y() * hchange); - - tmp = QRect(x, y, width, height); - positions[i] = tmp; + QRect tmp = unbiasedpos[i]; + positions[i] = + QRect((int)round(tmp.x() * wmult), + (int)round(tmp.y() * hmult), + (int)ceil( tmp.width() * wmult), + (int)ceil( tmp.height() * hmult)); } } -void OSDTypePositionRectangle::AddPosition(QRect rect) +void OSDTypePositionRectangle::AddPosition( + QRect rect, float wmult, float hmult) { positions.push_back(rect); + unbiasedpos.push_back( + QRect((int)round(rect.x() / wmult), + (int)round(rect.y() / hmult), + (int)ceil( rect.width() / wmult), + (int)ceil( rect.height() / hmult))); m_numpositions++; } -void OSDTypePositionRectangle::Draw(OSDSurface *surface, int fade, int maxfade, - int xoff, int yoff) +void OSDTypePositionRectangle::Draw( + OSDSurface *surface, int fade, int maxfade, int xoff, int yoff) { fade = fade; maxfade = maxfade; @@ -1618,17 +1657,21 @@ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OSDTypePositionImage::OSDTypePositionImage(const QString &name) - : OSDTypeImage(name), OSDTypePositionIndicator() + : OSDTypeImage(name), OSDTypePositionIndicator(), + m_wmult(0.0f), m_hmult(0.0f) { } OSDTypePositionImage::OSDTypePositionImage(const OSDTypePositionImage &other) : OSDTypeImage(other), OSDTypePositionIndicator(other) { + m_wmult = other.m_wmult; + m_hmult = other.m_hmult; + for (int i = 0; i < m_numpositions; i++) { - QPoint tmp = other.positions[i]; - positions.push_back(tmp); + positions.push_back(other.positions[i]); + unbiasedpos.push_back(other.unbiasedpos[i]); } } @@ -1636,45 +1679,61 @@ { } -void OSDTypePositionImage::Reinit(float wchange, float hchange, float wmult, - float hmult) +void OSDTypePositionImage::Reinit(float wmult, float hmult) { - OSDTypeImage::Reinit(wchange, hchange, wmult, hmult); + m_wmult = wmult; + m_hmult = hmult; + + OSDTypeImage::Reinit(wmult, hmult); for (int i = 0; i < m_numpositions; i++) { - QPoint tmp = positions[i]; - - int x = (int)(tmp.x() * wchange); - int y = (int)(tmp.y() * hchange); - - positions[i].setX(x); - positions[i].setY(y); + positions[i] = + QPoint((int)round(unbiasedpos[i].x() * wmult), + (int)round(unbiasedpos[i].y() * hmult)); } } -void OSDTypePositionImage::AddPosition(QPoint pos) +void OSDTypePositionImage::AddPosition(QPoint pos, float wmult, float hmult) { + if (m_wmult == 0.0f || m_hmult == 0.0f) + { + m_wmult = wmult; + m_hmult = hmult; + } positions.push_back(pos); + unbiasedpos.push_back( + QPoint((int)round(pos.x() / wmult), + (int)round(pos.y() / hmult))); + + VERBOSE(VB_IMPORTANT, + "OSDTypePositionImage::AddPosition["<= m_numpositions) return; QPoint pos = positions[m_curposition]; - OSDTypeImage::SetPosition(pos); + OSDTypeImage::SetPosition(pos, m_wmult, m_hmult); OSDTypeImage::Draw(surface, fade, maxfade, xoff, yoff); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OSDTypeCC::OSDTypeCC(const QString &name, TTFFont *font, int xoff, int yoff, - int dispw, int disph) + int dispw, int disph, float wmult, float hmult) : OSDType(name) { m_font = font; @@ -1683,9 +1742,11 @@ yoffset = yoff; displaywidth = dispw; displayheight = disph; + m_wmult = wmult; + m_hmult = hmult; QRect rect = QRect(0, 0, 0, 0); - m_box = new OSDTypeBox("cc_background", rect); + m_box = new OSDTypeBox("cc_background", rect, wmult, hmult); m_ccbackground = gContext->GetNumSetting("CCBackground", 0); } @@ -1695,12 +1756,23 @@ delete m_box; } -void OSDTypeCC::Reinit(int x, int y, int dispw, int disph) +void OSDTypeCC::Reinit(float wmult, float hmult) { + (void) wmult; + (void) hmult; + VERBOSE(VB_IMPORTANT, "Programmer error: " + "Call to OSDTypeCC::Reinit(float,float)"); +} + +void OSDTypeCC::Reinit(int x, int y, int dispw, int disph, + float wmult, float hmult) +{ xoffset = x; yoffset = y; displaywidth = dispw; displayheight = disph; + m_wmult = wmult; + m_hmult = hmult; } void OSDTypeCC::AddCCText(const QString &text, int x, int y, int color, @@ -1875,7 +1947,7 @@ { QRect rect = QRect(0, 0, textlength + 4, (m_font->Size() * 3 / 2) + 3); - m_box->SetRect(rect); + m_box->SetRect(rect, m_wmult, m_hmult); m_box->Draw(surface, 0, 0, x - 2, y - 2); } Index: mythtv/libs/libmythtv/tv_play.cpp =================================================================== --- mythtv/libs/libmythtv/tv_play.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/tv_play.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -247,7 +247,7 @@ browsechannum(""), browsechanid(""), browsestarttime(""), // Program Info for currently playing video recorderPlaybackInfo(NULL), - playbackinfo(NULL), inputFilename(""), playbackLen(0), + playbackinfo(NULL), playbackLen(0), lastProgram(NULL), jumpToProgram(false), // Video Players nvp(NULL), pipnvp(NULL), activenvp(NULL), @@ -578,19 +578,7 @@ if (!testrec->IsValidRecorder()) { if (showDialogs) - { - QString title = tr("MythTV is already using all available " - "inputs for recording. If you want to " - "watch an in-progress recording, select one " - "from the playback menu. If you want to " - "watch live TV, cancel one of the " - "in-progress recordings from the delete " - "menu."); - - DialogBox diag(gContext->GetMainWindow(), title); - diag.AddButton(tr("Cancel and go back to the TV menu")); - diag.exec(); - } + ShowNoRecorderDialog(); delete testrec; @@ -659,8 +647,6 @@ if (internalState != kState_None) return 0; - inputFilename = rcinfo->pathname; - playbackLen = rcinfo->CalculateLength(); playbackinfo = new ProgramInfo(*rcinfo); @@ -844,9 +830,10 @@ } else { + QString playbackURL = playbackinfo->GetPlaybackURL(); + tvchain->SetProgram(playbackinfo); - - prbuffer = new RingBuffer(playbackinfo->pathname, false); + prbuffer = new RingBuffer(playbackURL, false); prbuffer->SetLiveMode(tvchain); } @@ -895,7 +882,14 @@ else if (TRANSITION(kState_None, kState_WatchingPreRecorded) || TRANSITION(kState_None, kState_WatchingRecording)) { - prbuffer = new RingBuffer(inputFilename, false); + QString playbackURL; + if ((playbackinfo->pathname.left(4) == "dvd:") || + (playbackinfo->isVideo)) + playbackURL = playbackinfo->pathname; + else + playbackURL = playbackinfo->GetPlaybackURL(); + + prbuffer = new RingBuffer(playbackURL, false); if (prbuffer->IsOpen()) { gContext->DisableScreensaver(); @@ -924,7 +918,7 @@ { QString message = "COMMFLAG_REQUEST "; message += playbackinfo->chanid + " " + - playbackinfo->startts.toString(Qt::ISODate); + playbackinfo->recstartts.toString(Qt::ISODate); RemoteSendMessage(message); } } @@ -1222,10 +1216,10 @@ nvp->SetParentPlayer(this); nvp->SetRingBuffer(prbuffer); nvp->SetRecorder(recorder); - nvp->SetAudioSampleRate(gContext->GetNumSetting("AudioSampleRate")); + nvp->SetAudioSampleRate(gContext->GetNumSetting("AudioSampleRate", 44100)); nvp->SetAudioDevice(gContext->GetSetting("AudioOutputDevice")); nvp->SetLength(playbackLen); - nvp->SetExactSeeks(gContext->GetNumSetting("ExactSeeking")); + nvp->SetExactSeeks(gContext->GetNumSetting("ExactSeeking", 0)); nvp->SetAutoCommercialSkip(autoCommercialSkip); nvp->SetLiveTVChain(tvchain); @@ -1296,9 +1290,9 @@ pipnvp->SetAsPIP(); pipnvp->SetRingBuffer(piprbuffer); pipnvp->SetRecorder(piprecorder); - pipnvp->SetAudioSampleRate(gContext->GetNumSetting("AudioSampleRate")); + pipnvp->SetAudioSampleRate(gContext->GetNumSetting("AudioSampleRate", 44100)); pipnvp->SetAudioDevice(gContext->GetSetting("AudioOutputDevice")); - pipnvp->SetExactSeeks(gContext->GetNumSetting("ExactSeeking")); + pipnvp->SetExactSeeks(gContext->GetNumSetting("ExactSeeking", 0)); pipnvp->SetLiveTVChain(piptvchain); pipnvp->SetLength(playbackLen); @@ -1454,6 +1448,30 @@ lastSignalMsg.clear(); } UpdateOSDTimeoutMessage(); + + if (!tvchainUpdate.isEmpty()) + { + tvchainUpdateLock.lock(); + for (QStringList::Iterator it = tvchainUpdate.begin(); + it != tvchainUpdate.end(); ++it) + { + if (tvchain && nvp && *it == tvchain->GetID()) + { + tvchain->ReloadAll(); + if (nvp->GetTVChain()) + nvp->CheckTVChain(); + } + if (piptvchain && pipnvp && *it == piptvchain->GetID()) + { + piptvchain->ReloadAll(); + if (pipnvp->GetTVChain()) + pipnvp->CheckTVChain(); + } + } + tvchainUpdate.clear(); + tvchainUpdateLock.unlock(); + } + osdlock.unlock(); } @@ -2743,7 +2761,7 @@ speedStr = QString("%1X").arg(normal_speed); struct StatusPosInfo posInfo; - nvp->calcSliderPos(posInfo); + nvp->calcSliderPos(posInfo, true); QDateTime respDate = mythCurrentDateTime(); QString infoStr = ""; @@ -2806,8 +2824,10 @@ } else { + QString playbackURL = playbackinfo->GetPlaybackURL(); + piptvchain->SetProgram(playbackinfo); - piprbuffer = new RingBuffer(playbackinfo->pathname, false); + piprbuffer = new RingBuffer(playbackURL, false); piprbuffer->SetLiveMode(piptvchain); } @@ -3472,8 +3492,10 @@ } else { + QString playbackURL = playbackinfo->GetPlaybackURL(); + tvchain->SetProgram(playbackinfo); - prbuffer = new RingBuffer(playbackinfo->pathname, false); + prbuffer = new RingBuffer(playbackURL, false); prbuffer->SetLiveMode(tvchain); } @@ -4627,7 +4649,8 @@ normal_speed = new_normal_speed; - activenvp->Play(normal_speed, true); + if (!paused) + activenvp->Play(normal_speed, true); QString text = QString(tr("Time Stretch %1X")).arg(normal_speed); @@ -4911,29 +4934,14 @@ } else if (tvchain && message.left(12) == "LIVETV_CHAIN") { - // Get osdlock, while intended for the OSD this ensures that - // the nvp & pipnvp are not deleted while we are using it.. - while (!osdlock.tryLock() && nvp) - usleep(2500); - message = message.simplifyWhiteSpace(); QStringList tokens = QStringList::split(" ", message); if (tokens[1] == "UPDATE") { - if (tvchain && nvp && tokens[2] == tvchain->GetID()) - { - tvchain->ReloadAll(); - if (nvp->GetTVChain()) - nvp->CheckTVChain(); - } - if (piptvchain && pipnvp && tokens[2] == piptvchain->GetID()) - { - piptvchain->ReloadAll(); - if (pipnvp->GetTVChain()) - pipnvp->CheckTVChain(); - } + tvchainUpdateLock.lock(); + tvchainUpdate += QDeepCopy(tokens[2]); + tvchainUpdateLock.unlock(); } - osdlock.unlock(); } else if (nvp && message.left(12) == "EXIT_TO_MENU") { @@ -4983,7 +4991,7 @@ QDateTime evstartts = QDateTime::fromString(tokens[2], Qt::ISODate); if ((playbackinfo->chanid == evchanid) && - (playbackinfo->startts == evstartts)) + (playbackinfo->recstartts == evstartts)) { QString msg = "COMMFLAG_REQUEST "; msg += tokens[1] + " " + tokens[2]; @@ -5000,7 +5008,7 @@ QDateTime evstartts = QDateTime::fromString(tokens[2], Qt::ISODate); if ((playbackinfo->chanid == evchanid) && - (playbackinfo->startts == evstartts)) + (playbackinfo->recstartts == evstartts)) { QMap newMap; QStringList mark; @@ -6067,9 +6075,22 @@ "in-progress recordings from the delete " "menu."); - MythPopupBox::showOkPopup( + if (embedWinID) + { + VERBOSE(VB_IMPORTANT, errorText); + } + else if (GetOSD()) + { + dialogname = "infobox"; + QStringList options("OK"); + GetOSD()->NewDialogBox(dialogname, errorText, options, 0); + } + else + { + MythPopupBox::showOkPopup( gContext->GetMainWindow(), QObject::tr("Channel Change Error"), errorText); + } } /** \fn TV::PauseLiveTV(void) Index: mythtv/libs/libmythtv/jobqueue.cpp =================================================================== --- mythtv/libs/libmythtv/jobqueue.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/jobqueue.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -275,6 +275,11 @@ (hostname != "") && (hostname != m_hostname)) { + // Setting the status here will prevent us from processing + // any other jobs for this recording until this one is + // completed on the remote host. + jobStatus[key] = status; + message = QString("JobQueue: Skipping '%1' job for chanid " "%2 @ %3, should run on '%4' instead") .arg(JobText(type)) Index: mythtv/libs/libmythtv/dvbdev/dvbdev.c =================================================================== --- mythtv/libs/libmythtv/dvbdev/dvbdev.c (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/dvbdev/dvbdev.c (.../branches/release-0-19-fixes) (revision 10931) @@ -29,55 +29,79 @@ const char* dvbdevice(int type, int cardnum) { - char* frontenddev[4] = + char* frontenddev[8] = { "/dev/dvb/adapter0/frontend0", "/dev/dvb/adapter1/frontend0", "/dev/dvb/adapter2/frontend0", - "/dev/dvb/adapter3/frontend0" + "/dev/dvb/adapter3/frontend0", + "/dev/dvb/adapter4/frontend0", + "/dev/dvb/adapter5/frontend0", + "/dev/dvb/adapter6/frontend0", + "/dev/dvb/adapter7/frontend0", }; - char* dvrdev[4] = + char* dvrdev[8] = { "/dev/dvb/adapter0/dvr0", "/dev/dvb/adapter1/dvr0", "/dev/dvb/adapter2/dvr0", - "/dev/dvb/adapter3/dvr0" + "/dev/dvb/adapter3/dvr0", + "/dev/dvb/adapter4/dvr0", + "/dev/dvb/adapter5/dvr0", + "/dev/dvb/adapter6/dvr0", + "/dev/dvb/adapter7/dvr0", }; - char* demuxdev[4] = + char* demuxdev[8] = { "/dev/dvb/adapter0/demux0", "/dev/dvb/adapter1/demux0", "/dev/dvb/adapter2/demux0", - "/dev/dvb/adapter3/demux0" + "/dev/dvb/adapter3/demux0", + "/dev/dvb/adapter4/demux0", + "/dev/dvb/adapter5/demux0", + "/dev/dvb/adapter6/demux0", + "/dev/dvb/adapter7/demux0", }; - char* cadev[4] = + char* cadev[8] = { "/dev/dvb/adapter0/ca0", "/dev/dvb/adapter1/ca0", "/dev/dvb/adapter2/ca0", - "/dev/dvb/adapter3/ca0" + "/dev/dvb/adapter3/ca0", + "/dev/dvb/adapter4/ca0", + "/dev/dvb/adapter5/ca0", + "/dev/dvb/adapter6/ca0", + "/dev/dvb/adapter7/ca0", }; - char* audiodev[4] = + char* audiodev[8] = { "/dev/dvb/adapter0/audio0", "/dev/dvb/adapter1/audio0", "/dev/dvb/adapter2/audio0", - "/dev/dvb/adapter3/audio0" + "/dev/dvb/adapter3/audio0", + "/dev/dvb/adapter4/audio0", + "/dev/dvb/adapter5/audio0", + "/dev/dvb/adapter6/audio0", + "/dev/dvb/adapter7/audio0", }; - char* videodev[4] = + char* videodev[8] = { "/dev/dvb/adapter0/video0", "/dev/dvb/adapter1/video0", "/dev/dvb/adapter2/video0", - "/dev/dvb/adapter3/video0" + "/dev/dvb/adapter3/video0", + "/dev/dvb/adapter4/video0", + "/dev/dvb/adapter5/video0", + "/dev/dvb/adapter6/video0", + "/dev/dvb/adapter7/video0", }; - if (cardnum > 3) + if (cardnum > 7) return 0; switch(type) Index: mythtv/libs/libmythtv/videosource.h =================================================================== --- mythtv/libs/libmythtv/videosource.h (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/videosource.h (.../branches/release-0-19-fixes) (revision 10931) @@ -75,6 +75,7 @@ static CARD_TYPES GetDVBType(uint device, QString &name, QString &card_type); static bool HasDVBCRCBug(uint device); + static uint GetMinSignalMonitoringDelay(uint device); static QString GetDefaultInput(uint cardid); static bool IgnoreEncrypted(uint cardid, const QString &inputname); Index: mythtv/libs/libmythtv/libmythtv.pro =================================================================== --- mythtv/libs/libmythtv/libmythtv.pro (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/libmythtv.pro (.../branches/release-0-19-fixes) (revision 10931) @@ -119,6 +119,10 @@ SOURCES += playgroup.cpp SOURCES += progdetails.cpp +# C stuff +HEADERS += frequencies.h +SOURCES += frequencies.c + using_frontend { # Recording profile stuff HEADERS += profilegroup.h @@ -144,10 +148,10 @@ # On screen display (video output overlay) HEADERS += osd.h osdtypes.h HEADERS += osdsurface.h osdlistbtntype.h - HEADERS += udpnotify.h + HEADERS += osdimagecache.h udpnotify.h SOURCES += osd.cpp osdtypes.cpp SOURCES += osdsurface.cpp osdlistbtntype.cpp - SOURCES += udpnotify.cpp + SOURCES += osdimagecache.cpp udpnotify.cpp # Video output HEADERS += videooutbase.h videoout_null.h @@ -303,10 +307,6 @@ } } - # C stuff - HEADERS += frequencies.h - SOURCES += frequencies.c - DEFINES += USING_BACKEND } Index: mythtv/libs/libmythtv/dvbchannel.cpp =================================================================== --- mythtv/libs/libmythtv/dvbchannel.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/dvbchannel.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -74,14 +74,27 @@ * \bug Only supports single input cards. */ DVBChannel::DVBChannel(int aCardNum, TVRec *parent) - : QObject(NULL, "DVBChannel"), ChannelBase(parent), - diseqc(NULL), dvbcam(NULL), - fd_frontend(-1), cardnum(aCardNum), has_crc_bug(false), - currentTID(-1), first_tune(true) + : QObject(NULL, "DVBChannel"), ChannelBase(parent), + diseqc(NULL), dvbcam(NULL), + fd_frontend(-1), cardnum(aCardNum), + has_crc_bug(false), + tuning_delay(0), sigmon_delay(25), + currentTID(-1), first_tune(true), + retune_adj(-10) { dvbcam = new DVBCam(cardnum); bzero(&info, sizeof(info)); has_crc_bug = CardUtil::HasDVBCRCBug(aCardNum); + + QString name(""), type(""); + CardUtil::GetDVBType(aCardNum, name, type); + if ((name == "DiBcom 3000P/M-C DVB-T") || + (name == "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver")) + { + tuning_delay = 200; + } + + sigmon_delay = CardUtil::GetMinSignalMonitoringDelay(aCardNum); } DVBChannel::~DVBChannel() @@ -367,7 +380,7 @@ } bool found = false; - int mplexid; + int mplexid = 0; while (query.next()) { int this_inputid = query.value(4).toInt(); @@ -633,7 +646,8 @@ * This is used by DVB Channel Scanner, the EIT Parser, and by TVRec. * * \param channel Info on transport to tune to - * \param force_reset If true frequency tuning is done even if not strictly needed + * \param force_reset If true, frequency tuning is done + * even if it should not be needed. * \return true on success, false on failure */ bool DVBChannel::Tune(const dvb_channel_t& channel, bool force_reset) @@ -642,6 +656,8 @@ bool has_diseq = (FE_QPSK == info.type) && diseqc; struct dvb_frontend_parameters params = channel.tuning.params; + retune_tuning = channel.tuning; + if (fd_frontend < 0) { ERROR("DVBChannel::Tune: Card not open!"); @@ -669,15 +685,22 @@ // Adjust for Satelite recievers which offset the frequency. params.frequency = tuned_frequency(channel.tuning, info.type, NULL); + params.frequency = params.frequency + (retune_adj = -retune_adj); + if (ioctl(fd_frontend, FE_SET_FRONTEND, ¶ms) < 0) { ERRNO("DVBChannel::Tune: " "Setting Frontend tuning parameters failed."); return false; } + + // Extra delay to add for broken DVB drivers + if (tuning_delay) + usleep(tuning_delay * 1000); + wait_for_backend(fd_frontend, 5 /* msec */); - prev_tuning.params = params; + prev_tuning.params = channel.tuning.params; first_tune = false; } @@ -686,6 +709,24 @@ return true; } +/** \fn DVBChannel::Retune(void) + * \brief Calls DVBChannel::Tune() with the last known parameters + * + * This is used to retune DVB-C hardware. DVB-C hardware + * sometimes does not successfully tune the first time + * despite reports of success from the drivers. This is + * probably a hardware problem and not a driver problem + * per say, so it is unlikely to be fixed at a lower level. + * + * \return true iff drivers report that tuning was successful + */ +bool DVBChannel::Retune(void) +{ + dvb_channel_t retune_channel; + retune_channel.tuning = retune_tuning; + return Tune(retune_channel, true); +} + /** \fn DVBChannel::GetTuningParams(DVBTuning& tuning) const * \brief Fetches DVBTuning params from driver * \return true on success, false on failure @@ -855,6 +896,9 @@ for (uint i = 0; i < 64 && !tuned; i++) if (!diseqc->Set(t, reset, tuned)) return false; - + + // Wait 10 ms, recommended by Marcus Metzler, see #1552 + usleep(10 * 1000); + return true; } Index: mythtv/libs/libmythtv/osdtypes.h =================================================================== --- mythtv/libs/libmythtv/osdtypes.h (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/osdtypes.h (.../branches/release-0-19-fixes) (revision 10931) @@ -8,6 +8,7 @@ #include #include #include +#include "osdimagecache.h" using namespace std; @@ -137,6 +138,8 @@ QString Name() { return m_name; } + virtual void Reinit(float wmult, float hmult) = 0; + virtual void Draw(OSDSurface *surface, int fade, int maxfade, int xoff, int yoff) = 0; @@ -150,11 +153,11 @@ { public: OSDTypeText(const QString &name, TTFFont *font, const QString &text, - QRect displayrect); + QRect displayrect, float wmult, float hmult); OSDTypeText(const OSDTypeText &text); ~OSDTypeText(); - void Reinit(float wchange, float hchange); + void Reinit(float wmult, float hmult); void SetAltFont(TTFFont *font); void SetUseAlt(bool usealt) { m_usingalt = usealt; } @@ -190,6 +193,7 @@ QRect m_displaysize; QRect m_screensize; + QRect m_unbiasedsize; QString m_message; QString m_default_msg; @@ -231,7 +235,7 @@ virtual ~OSDTypeImage(); void SetName(const QString &name); - void Reinit(float wchange, float hchange, float wmult, float hmult); + void Reinit(float wmult, float hmult); void LoadImage(const QString &filename, float wmult, float hmult, int scalew = -1, int scaleh = -1); @@ -239,21 +243,20 @@ void SetStaticSize(int scalew, int scaleh) { m_scalew = scalew; m_scaleh = scaleh; } + void SetPosition(QPoint pos, float wmult, float hmult); - QPoint DisplayPos() { return m_displaypos; } - void SetPosition(QPoint pos) { m_displaypos = pos; } + QPoint DisplayPos() const { return m_displaypos; } + QRect ImageSize() const { return m_imagesize; } + int width() const { return m_imagesize.width(); } + int height() const { return m_imagesize.height(); } - QRect ImageSize() { return m_imagesize; } - - int width() { return m_imagesize.width(); } - int height() { return m_imagesize.height(); } - virtual void Draw(OSDSurface *surface, int fade, int maxfade, int xoff, int yoff); protected: QRect m_imagesize; QPoint m_displaypos; + QPoint m_unbiasedpos; QString m_filename; @@ -270,6 +273,9 @@ int m_drawwidth; bool m_onlyusefirst; + + static OSDImageCache c_cache; + OSDImageCacheValue *m_cacheitem; }; class OSDTypePosSlider : public OSDTypeImage @@ -280,7 +286,7 @@ int scalew = -1, int scaleh = -1); ~OSDTypePosSlider(); - void Reinit(float wchange, float hchange, float wmult, float hmult); + void Reinit(float wmult, float hmult); void SetRectangle(QRect rect) { m_displayrect = rect; } QRect ImageSize() { return m_imagesize; } @@ -290,6 +296,7 @@ private: QRect m_displayrect; + QRect m_unbiasedrect; int m_maxval; int m_curval; }; @@ -302,7 +309,7 @@ int scalew = -1, int scaleh = -1); ~OSDTypeFillSlider(); - void Reinit(float wchange, float hchange, float wmult, float hmult); + void Reinit(float wmult, float hmult); void SetRectangle(QRect rect) { m_displayrect = rect; } QRect ImageSize() { return m_imagesize; } @@ -314,6 +321,7 @@ private: QRect m_displayrect; + QRect m_unbiasedrect; int m_maxval; int m_curval; }; @@ -327,7 +335,7 @@ int scalew = -1, int scaleh = -1); ~OSDTypeEditSlider(); - void Reinit(float wchange, float hchange, float wmult, float hmult); + void Reinit(float wmult, float hmult); void SetRectangle(QRect rect) { m_displayrect = rect; } QRect ImageSize() { return m_imagesize; } @@ -339,6 +347,7 @@ private: QRect m_displayrect; + QRect m_unbiasedrect; int m_maxval; int m_curval; @@ -360,17 +369,19 @@ class OSDTypeBox : public OSDType { public: - OSDTypeBox(const QString &name, QRect displayrect); + OSDTypeBox(const QString &name, QRect displayrect, + float wmult, float hmult); OSDTypeBox(const OSDTypeBox &other); ~OSDTypeBox(); - void Reinit(float wchange, float hchange); - void SetRect(QRect newrect) { size = newrect; } + void Reinit(float wmult, float hmult); + void SetRect(QRect newrect, float wmult, float hmult); void Draw(OSDSurface *surface, int fade, int maxfade, int xoff, int yoff); private: QRect size; + QRect m_unbiasedsize; }; class OSDTypePositionIndicator @@ -403,14 +414,15 @@ OSDTypePositionRectangle(const OSDTypePositionRectangle &other); ~OSDTypePositionRectangle(); - void AddPosition(QRect rect); + void AddPosition(QRect rect, float wmult, float hmult); - void Reinit(float wchange, float hchange); + void Reinit(float wmult, float hmult); void Draw(OSDSurface *surface, int fade, int maxfade, int xoff, int yoff); private: - vector positions; + vector positions; + vector unbiasedpos; }; class OSDTypePositionImage : public virtual OSDTypeImage, @@ -421,14 +433,17 @@ OSDTypePositionImage(const OSDTypePositionImage &other); ~OSDTypePositionImage(); - void Reinit(float wchange, float hchange, float wmult, float hmult); + void Reinit(float wmult, float hmult); - void AddPosition(QPoint pos); + void AddPosition(QPoint pos, float wmult, float hmult); void Draw(OSDSurface *surface, int fade, int maxfade, int xoff, int yoff); private: vector positions; + vector unbiasedpos; + float m_wmult; + float m_hmult; }; class ccText @@ -445,11 +460,15 @@ { public: OSDTypeCC(const QString &name, TTFFont *font, int xoff, int yoff, - int dispw, int disph); + int dispw, int disph, float wmult, float hmult); ~OSDTypeCC(); - void Reinit(int xoff, int yoff, int dispw, int disph); + void Reinit(float wmult, float hmult); + void Reinit(int xoff, int yoff, + int dispw, int disph, + float wmult, float hmult); + void AddCCText(const QString &text, int x, int y, int color, bool teletextmode = false); void ClearAllCCText(); @@ -464,7 +483,7 @@ vector *m_textlist; OSDTypeBox *m_box; int m_ccbackground; - + float m_wmult, m_hmult; int xoffset, yoffset, displaywidth, displayheight; }; Index: mythtv/libs/libmythtv/videoout_xv.h =================================================================== --- mythtv/libs/libmythtv/videoout_xv.h (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/videoout_xv.h (.../branches/release-0-19-fixes) (revision 10931) @@ -80,6 +80,8 @@ virtual bool hasVLDAcceleration(void) const { return XVideoVLD == VideoOutputSubType(); } + void CheckFrameStates(void); + static MythCodecID GetBestSupportedCodec(uint width, uint height, uint osd_width, uint osd_height, uint stream_type, int xvmc_chroma, @@ -141,7 +143,7 @@ static bool IsRendering(VideoFrame* frame); static void SyncSurface(VideoFrame* frame, int past_future = 0); static void FlushSurface(VideoFrame* frame); - void CheckDisplayedFramesForAvailability(void); + #ifdef USING_XVMC XvMCOSD* GetAvailableOSD(); void ReturnAvailableOSD(XvMCOSD*); Index: mythtv/libs/libmythtv/osdimagecache.h =================================================================== --- mythtv/libs/libmythtv/osdimagecache.h (.../tags/release-0-19) (revision 0) +++ mythtv/libs/libmythtv/osdimagecache.h (.../branches/release-0-19-fixes) (revision 10931) @@ -0,0 +1,74 @@ +// -*- Mode: c++ -*- + +// POSIX headers +#include + +// Qt headers +#include +#include +#include +#include +#include + +class OSDImageCacheValue +{ + public: + OSDImageCacheValue(QString cacheKey, + unsigned char *yuv, unsigned char *ybuffer, + unsigned char *ubuffer, unsigned char *vbuffer, + unsigned char *alpha, QRect imagesize); + + virtual ~OSDImageCacheValue(); + + uint GetSize(void) const { return m_size_in_bytes; } + QString GetKey(void) const { return m_cacheKey; } + + public: + unsigned char *m_yuv; + unsigned char *m_ybuffer; + unsigned char *m_ubuffer; + unsigned char *m_vbuffer; + unsigned char *m_alpha; + QRect m_imagesize; + + private: + uint m_size_in_bytes; + QString m_cacheKey; +}; + +typedef QAsciiCache img_cache_t; + +class OSDImageCache +{ + public: + OSDImageCache(); + virtual ~OSDImageCache(); + + bool InFileCache(const QString &key) const; + + bool Contains(const QString &key, bool useFile) const; + + OSDImageCacheValue *Get(const QString &key, bool useFile); + + void Insert(OSDImageCacheValue* value); + + void SaveToDisk(const OSDImageCacheValue *value); + + void Reset(void); + + static QString CreateKey(const QString &filename, + float wmult, float hmult, + int scalew, int scaleh); + + static QString ExtractOriginal(const QString &key); + + private: + mutable QMutex m_cacheLock; + img_cache_t m_imageCache; + int m_memHits; + int m_diskHits; + int m_misses; + + /// Limit on the maximum total size of OSD images cached in *memory*. + static uint kMaximumMemoryCacheSize; +}; Index: mythtv/libs/libmythtv/tv_play.h =================================================================== --- mythtv/libs/libmythtv/tv_play.h (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/tv_play.h (.../branches/release-0-19-fixes) (revision 10931) @@ -456,7 +456,6 @@ ProgramInfo *recorderPlaybackInfo; ///< info requested from recorder ProgramInfo *playbackinfo; ///< info sent in via Playback() QMutex pbinfoLock; - QString inputFilename; ///< playbackinfo->pathname int playbackLen; ///< initial playbackinfo->CalculateLength() ProgramInfo *lastProgram; ///< last program played with this player bool jumpToProgram; @@ -485,6 +484,8 @@ // LiveTVChain LiveTVChain *tvchain; LiveTVChain *piptvchain; + QStringList tvchainUpdate; + QMutex tvchainUpdateLock; // RingBuffers RingBuffer *prbuffer; Index: mythtv/libs/libmythtv/videosource.cpp =================================================================== --- mythtv/libs/libmythtv/videosource.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/videosource.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -32,6 +32,7 @@ #include "videosource.h" #include "datadirect.h" #include "scanwizard.h" +#include "frequencies.h" #ifdef USING_DVB #include @@ -156,6 +157,17 @@ (name == "ST STV0299 DVB-S")); // munges PAT } +uint CardUtil::GetMinSignalMonitoringDelay(uint device) +{ + QString name(""), type(""); + GetDVBType(device, name, type); + if (name.find("DVB-S") >= 0) + return 300; + if (name == "DiBcom 3000P/M-C DVB-T") + return 100; + return 25; +} + /** \fn CardUtil::GetCardType(uint, QString&, QString&) * \brief Returns the card type from the video device * \param nCardID cardid of card to be checked @@ -574,22 +586,10 @@ { setLabel(QObject::tr("Channel frequency table")); addSelection("default"); - addSelection("us-cable"); - addSelection("us-bcast"); - addSelection("us-cable-hrc"); - addSelection("japan-bcast"); - addSelection("japan-cable"); - addSelection("europe-west"); - addSelection("europe-east"); - addSelection("italy"); - addSelection("newzealand"); - addSelection("australia"); - addSelection("ireland"); - addSelection("france"); - addSelection("china-bcast"); - addSelection("southafrica"); - addSelection("argentina"); - addSelection("australia-optus"); + + for (uint i = 0; chanlists[i].name; i++) + addSelection(chanlists[i].name); + setHelpText(QObject::tr("Use default unless this source uses a " "different frequency table than the system wide table " "defined in the General settings.")); Index: mythtv/libs/libmythtv/frequencytables.cpp =================================================================== --- mythtv/libs/libmythtv/frequencytables.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/frequencytables.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -283,104 +283,52 @@ "ATSC Channel %1", 70, 809000000, 887000000, 6000000, VSB_8); #endif // USING_DVB - // USA Cable, QAM 256 - fmap["atsc_qam256_uscable0"] = new FrequencyTable( - "QAM-256 Channel %1", 1, 75000000,1005000000, 6000000, QAM_256); - fmap["atsc_qam256_uscable1"] = new FrequencyTable( - "QAM-256 Channel T-%1", 7, 10000000, 52000000, 6000000, QAM_256); + QString modStr[] = { "vsb8", "qam256", "qam128", "qam64", }; + uint mod[] = { VSB_8, QAM_256, QAM_128, QAM_64, }; + QString desc[] = { "ATSC ", "QAM-256 ", "QAM-128 ", "QAM-64 ", }; - // USA Cable, QAM 256 ch 78+ - fmap["atsc_qam256_uscablehigh0"] = new FrequencyTable( - "QAM-256 Channel %1", 78,472000000,1005000000, 6000000, QAM_256); +#define FREQ(A,B, C,D, E,F,G, H) \ + fmap[QString("atsc_%1_us%2").arg(A).arg(B)] = \ + new FrequencyTable(C+D, E, F, G, 6000000, H); - // USA Cable HRC, QAM 256 - fmap["atsc_qam256_ushrc0"] = new FrequencyTable( - "QAM-256 HRC %1", 1, 73750000, 73750001, 6000000, QAM_256); - fmap["atsc_qam256_ushrc1"] = new FrequencyTable( - "QAM-256 HRC %1", 2, 55750000, 67750000, 6000000, QAM_256); - fmap["atsc_qam256_ushrc2"] = new FrequencyTable( - "QAM-256 HRC %1", 5, 79750000, 85750000, 6000000, QAM_256); - fmap["atsc_qam256_ushrc3"] = new FrequencyTable( - "QAM-256 HRC %1", 7, 175750000, 643750000, 6000000, QAM_256); - fmap["atsc_qam256_ushrc4"] = new FrequencyTable( - "QAM-256 HRC %1", 95, 91750000, 114000000, 6000000, QAM_256); - fmap["atsc_qam256_ushrc5"] = new FrequencyTable( - "QAM-256 HRC %1", 100, 649750000, 799750000, 6000000, QAM_256); - fmap["atsc_qam256_ushrc6"] = new FrequencyTable( - "QAM-256 HRC T-%1", 7, 8175000, 50750000, 6000000, QAM_256); + for (uint i = 0; i < 4; i++) + { + // USA Cable, ch 1 to 155 and T.7 to T.14 + FREQ(modStr[i], "cable0", desc[i], "Channel %1", + 1, 75000000, 1005000000, mod[i]); + FREQ(modStr[i], "cable1", desc[i], "Channel T-%1", + 7, 10000000, 52000000, mod[i]); + // USA Cable, QAM 256 ch 78 to 155 + FREQ(modStr[i], "cablehigh0", desc[i], "Channel %1", + 78, 537000000,1005000000, mod[i]); - // USA Cable HRC, QAM 256 ch 78+ - fmap["atsc_qam256_ushrchigh0"] = new FrequencyTable( - "QAM-256 HRC %1", 78, 601750000, 643750000, 6000000, QAM_256); - fmap["atsc_qam256_ushrchigh1"] = new FrequencyTable( - "QAM-256 HRC %1", 100, 649750000, 799750000, 6000000, QAM_256); + QString std[] = { "hrc", "irc" }; + QString sdesc[] = { "HRC ", "IRC " }; + int off[] = { 0, 1250000 }; + for (uint j = 0; j < 2; j++) + { + // USA Cable HRC/IRC, ch 1 to 125 + FREQ(modStr[i], std[j] + "0", desc[i], sdesc[j] + "%1", + 1, 73750000 + off[j], 73750001 + off[j], mod[i]); + FREQ(modStr[i], std[j] + "1", desc[i], sdesc[j] + "%1", + 2, 55750000 + off[j], 67750000 + off[j], mod[i]); + FREQ(modStr[i], std[j] + "2", desc[i], sdesc[j] + "%1", + 5, 79750000 + off[j], 85750000 + off[j], mod[i]); + FREQ(modStr[i], std[j] + "3", desc[i], sdesc[j] + "%1", + 7, 175750000 + off[j], 643750000 + off[j], mod[i]); + FREQ(modStr[i], std[j] + "4", desc[i], sdesc[j] + "%1", + 95, 91750000 + off[j], 114000000 + off[j], mod[i]); + FREQ(modStr[i], std[j] + "5", desc[i], sdesc[j] + "%1", + 100, 649750000 + off[j], 799750000 + off[j], mod[i]); + FREQ(modStr[i], std[j] + "6", desc[i], sdesc[j] + "T-%1", + 7, 8175000 + off[j], 50750000 + off[j], mod[i]); - - // USA Cable, QAM 128 - fmap["atsc_qam128_uscable0"] = new FrequencyTable( - "QAM-128 Channel %1", 1, 75000000,1005000000, 6000000, QAM_128); - fmap["atsc_qam128_uscable1"] = new FrequencyTable( - "QAM-128 Channel T-%1", 7, 10000000, 52000000, 6000000, QAM_128); - - // USA Cable, QAM 128 ch 78+ - fmap["atsc_qam128_uscablehigh0"] = new FrequencyTable( - "QAM-128 Channel %1", 78,472000000,1005000000, 6000000, QAM_128); - - // USA Cable HRC, QAM 128 - fmap["atsc_qam128_ushrc0"] = new FrequencyTable( - "QAM-128 HRC %1", 1, 73750000, 73750001, 6000000, QAM_128); - fmap["atsc_qam128_ushrc1"] = new FrequencyTable( - "QAM-128 HRC %1", 2, 55750000, 67750000, 6000000, QAM_128); - fmap["atsc_qam128_ushrc2"] = new FrequencyTable( - "QAM-128 HRC %1", 5, 79750000, 85750000, 6000000, QAM_128); - fmap["atsc_qam128_ushrc3"] = new FrequencyTable( - "QAM-128 HRC %1", 7, 175750000, 643750000, 6000000, QAM_128); - fmap["atsc_qam128_ushrc4"] = new FrequencyTable( - "QAM-128 HRC %1", 95, 91750000, 114000000, 6000000, QAM_128); - fmap["atsc_qam128_ushrc5"] = new FrequencyTable( - "QAM-128 HRC %1", 100, 649750000, 799750000, 6000000, QAM_128); - fmap["atsc_qam128_ushrc6"] = new FrequencyTable( - "QAM-128 HRC T-%1", 7, 8175000, 50750000, 6000000, QAM_128); - - // USA Cable HRC, QAM 128 ch 78+ - fmap["atsc_qam128_ushrchigh0"] = new FrequencyTable( - "QAM-128 HRC %1", 78, 601750000, 643750000, 6000000, QAM_128); - fmap["atsc_qam128_ushrchigh1"] = new FrequencyTable( - "QAM-128 HRC %1", 100, 649750000, 799750000, 6000000, QAM_128); - - - - - // USA Cable, QAM 64 - fmap["atsc_qam64_uscable0"] = new FrequencyTable( - "QAM-64 Channel %1", 1, 75000000,1005000000, 6000000, QAM_64); - fmap["atsc_qam64_uscable1"] = new FrequencyTable( - "QAM-64 Channel T-%1", 7, 10000000, 52000000, 6000000, QAM_64); - - // USA Cable, QAM 64 ch 78+ - fmap["atsc_qam64_uscablehigh0"] = new FrequencyTable( - "QAM-64 Channel %1", 78,472000000,1005000000, 6000000, QAM_64); - - // USA Cable HRC, QAM 64 - fmap["atsc_qam64_ushrc0"] = new FrequencyTable( - "QAM-64 HRC %1", 1, 73750000, 73750001, 6000000, QAM_64); - fmap["atsc_qam64_ushrc1"] = new FrequencyTable( - "QAM-64 HRC %1", 2, 55750000, 67750000, 6000000, QAM_64); - fmap["atsc_qam64_ushrc2"] = new FrequencyTable( - "QAM-64 HRC %1", 5, 79750000, 85750000, 6000000, QAM_64); - fmap["atsc_qam64_ushrc3"] = new FrequencyTable( - "QAM-64 HRC %1", 7, 175750000, 643750000, 6000000, QAM_64); - fmap["atsc_qam64_ushrc4"] = new FrequencyTable( - "QAM-64 HRC %1", 95, 91750000, 114000000, 6000000, QAM_64); - fmap["atsc_qam64_ushrc5"] = new FrequencyTable( - "QAM-64 HRC %1", 100, 649750000, 799750000, 6000000, QAM_64); - fmap["atsc_qam64_ushrc6"] = new FrequencyTable( - "QAM-64 HRC T-%1", 7, 8175000, 50750000, 6000000, QAM_64); - - // USA Cable HRC, QAM 64 ch 78+ - fmap["atsc_qam64_ushrchigh0"] = new FrequencyTable( - "QAM-64 HRC %1", 78, 601750000, 643750000, 6000000, QAM_64); - fmap["atsc_qam64_ushrchigh1"] = new FrequencyTable( - "QAM-64 HRC %1", 100, 649750000, 799750000, 6000000, QAM_64); + // USA Cable HRC/IRC, ch 67-125 + FREQ(modStr[i], std[j] + "high0", desc[i], sdesc[j] + "%1", + 67, 535750000 + off[j], 643750000 + off[j], mod[i]); + FREQ(modStr[i], std[j] + "high1", desc[i], sdesc[j] + "%1", + 100, 649750000 + off[j], 799750000 + off[j], mod[i]); + } + } } Index: mythtv/libs/libmythtv/scanwizardhelpers.h =================================================================== --- mythtv/libs/libmythtv/scanwizardhelpers.h (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/scanwizardhelpers.h (.../branches/release-0-19-fixes) (revision 10931) @@ -272,11 +272,13 @@ public: ScanFrequencyTable() { - addSelection(QObject::tr("Broadcast"), "us", true); - addSelection(QObject::tr("Cable") +" 78+", "uscablehigh", false); - addSelection(QObject::tr("Cable HRC")+" 78+", "uscablehrchigh",false); - addSelection(QObject::tr("Cable"), "uscable", false); - addSelection(QObject::tr("Cable HRC"), "ushrc", false); + addSelection(QObject::tr("Broadcast"), "us", true); + addSelection(QObject::tr("Cable") +" 78+", "uscablehigh", false); + addSelection(QObject::tr("Cable HRC")+" 67+", "ushrchigh", false); + addSelection(QObject::tr("Cable IRC")+" 67+", "usirchigh", false); + addSelection(QObject::tr("Cable"), "uscable", false); + addSelection(QObject::tr("Cable HRC"), "ushrc", false); + addSelection(QObject::tr("Cable IRC"), "usirc", false); setLabel(QObject::tr("Frequency Table")); setHelpText(QObject::tr("Frequency table to use.") + " " + Index: mythtv/libs/libmythtv/scanwizard.cpp =================================================================== --- mythtv/libs/libmythtv/scanwizard.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/scanwizard.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -518,7 +518,9 @@ "SELECT dvb_diseqc_type, diseqc_port, diseqc_pos, " " lnb_lof_switch, lnb_lof_hi, lnb_lof_lo " "FROM cardinput, capturecard " - "WHERE capturecard.cardid=%1 and cardinput.sourceid=%2") + "WHERE capturecard.cardid = %1 AND " + " cardinput.sourceid = %2 AND " + " capturecard.cardid = cardinput.cardid") .arg(parent->captureCard()).arg(nVideoSource)); if (query.exec() && query.isActive() && query.size() > 0) Index: mythtv/libs/libmythtv/videoout_xv.cpp =================================================================== --- mythtv/libs/libmythtv/videoout_xv.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/videoout_xv.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -1089,6 +1089,9 @@ bool use_xv = true, use_shm = true; QString dec = gContext->GetSetting("PreferredMPEG2Decoder", "ffmpeg"); + if (dec != "libmpeg2" && height < 720 && + gContext->GetNumSetting("UseXvMCForHDOnly", 0)) + dec = "ffmpeg"; if (dec == "xvmc") use_xvmc_idct = use_xvmc = true; else if (dec == "xvmc-vld") @@ -1335,40 +1338,39 @@ if (attributes) X11S(XFree(attributes)); - if (xv_draw_colorkey) + if (!xv_draw_colorkey) + return; + + QString msg = LOC + "Chromakeying not possible with this XVideo port."; + X11S(xv_atom = XInternAtom(XJ_disp, "XV_COLORKEY", False)); + if (xv_atom == None) { - X11S(xv_atom = XInternAtom(XJ_disp, "XV_COLORKEY", False)); - if (xv_atom != None) - { - X11S(ret = XvGetPortAttribute(XJ_disp, xv_port, xv_atom, - &xv_colorkey)); + VERBOSE(VB_PLAYBACK, msg); + xv_colorkey = 0; + return; + } - if (ret == Success && xv_colorkey == 0) - { - const int default_colorkey = 1; - X11S(ret = XvSetPortAttribute(XJ_disp, xv_port, xv_atom, - default_colorkey)); - if (ret == Success) - { - VERBOSE(VB_PLAYBACK, LOC + - "0,0,0 is the only bad color key for MythTV, " - "using "<p_past_surface = NULL; - //GetRender(*it)->p_future_surface = NULL; - } - VERBOSE(VB_PLAYBACK, LOC + QString("DiscardFrames() 2: %1") - .arg(vbuffers.GetStatus())); -#if 0 - // Remove inheritence of all frames not in displayed or pause - DQ_COPY(ula, kVideoBuffer_used); - DQ_COPY(ula, kVideoBuffer_limbo); - DQ_COPY(ula, kVideoBuffer_avail); - - for (it = ula.begin(); it != ula.end(); ++it) - vbuffers.RemoveInheritence(*it); -#endif - - VERBOSE(VB_PLAYBACK, LOC + QString("DiscardFrames() 3: %1") - .arg(vbuffers.GetStatus())); - // create discard frame list - DQ_COPY(discards, kVideoBuffer_used); - DQ_COPY(discards, kVideoBuffer_limbo); - - vbuffers.end_lock(); // Lock Y + SyncSurface(*it, -1); // sync past + SyncSurface(*it, +1); // sync future + SyncSurface(*it, 0); // sync current + vbuffers.safeEnqueue(kVideoBuffer_displayed, *it); } + syncs.clear(); + vbuffers.end_lock(); // Lock Y - for (it = discards.begin(); it != discards.end(); ++it) - DiscardFrame(*it); + CheckFrameStates(); + // If the next frame is a keyframe we can clear out a lot more... + if (next_frame_keyframe) { vbuffers.begin_lock(kVideoBuffer_displayed); // Lock Z - syncs.clear(); - DQ_COPY(syncs, kVideoBuffer_displayed); - DQ_COPY(syncs, kVideoBuffer_pause); + // Move all the limbo and pause frames to displayed + DQ_COPY(syncs, kVideoBuffer_limbo); for (it = syncs.begin(); it != syncs.end(); ++it) { SyncSurface(*it, -1); // sync past SyncSurface(*it, +1); // sync future SyncSurface(*it, 0); // sync current - //GetRender(*it)->p_past_surface = NULL; - //GetRender(*it)->p_future_surface = NULL; + vbuffers.safeEnqueue(kVideoBuffer_displayed, *it); } - VERBOSE(VB_PLAYBACK, LOC + - QString("DiscardFrames() 4: %1 -- done() ") + VERBOSE(VB_PLAYBACK, LOC + QString("DiscardFrames() 2: %1") .arg(vbuffers.GetStatus())); - + vbuffers.end_lock(); // Lock Z + + // Now call CheckFrameStates() to remove inheritence and + // move the surfaces to the used list if possible (i.e. + // if avlib is not using them and they are not currently + // being displayed on screen). + CheckFrameStates(); } + VERBOSE(VB_PLAYBACK, LOC + QString("DiscardFrames() 3: %1 -- done()") + .arg(vbuffers.GetStatus())); + #endif // USING_XVMC } @@ -2071,7 +2062,7 @@ if (osdframe) DiscardFrame(osdframe); } - CheckDisplayedFramesForAvailability(); + CheckFrameStates(); #endif } @@ -2411,7 +2402,7 @@ DiscardFrame(vbuffers.dequeue(kVideoBuffer_pause)); } // clear any displayed frames not on screen - CheckDisplayedFramesForAvailability(); + CheckFrameStates(); // unlock the frame[s] vbuffers.UnlockFrame(osdframe, "ShowXvMC -- OSD"); @@ -2659,7 +2650,7 @@ .arg(vbuffers.size(kVideoBuffer_pause))); while (vbuffers.size(kVideoBuffer_pause)) DiscardFrame(vbuffers.dequeue(kVideoBuffer_pause)); - CheckDisplayedFramesForAvailability(); + CheckFrameStates(); } else if (1 == vbuffers.size(kVideoBuffer_pause)) { VideoFrame *frame = vbuffers.dequeue(kVideoBuffer_used); @@ -2791,7 +2782,7 @@ // If there are no available buffer, try to toss old // displayed frames. if (!vbuffers.size(kVideoBuffer_avail)) - CheckDisplayedFramesForAvailability(); + CheckFrameStates(); // If tossing doesn't work try hiding showing frames, // then tossing displayed frames. @@ -2805,7 +2796,7 @@ GetRender(*it)->p_surface)); vbuffers.end_lock(); - CheckDisplayedFramesForAvailability(); + CheckFrameStates(); } // If there is an available buffer grab it. @@ -3013,7 +3004,7 @@ return -1; } -void VideoOutputXv::CheckDisplayedFramesForAvailability(void) +void VideoOutputXv::CheckFrameStates(void) { #ifdef USING_XVMC frame_queue_t::iterator it; @@ -3084,6 +3075,13 @@ } } } + else if (vbuffers.contains(kVideoBuffer_decode, pframe)) + { + VERBOSE(VB_PLAYBACK, LOC + QString( + "Frame %1 is in use by avlib and so is " + "being held for later discarding.") + .arg(DebugString(pframe, true))); + } else { vbuffers.RemoveInheritence(pframe); Index: mythtv/libs/libmythtv/signalmonitor.h =================================================================== --- mythtv/libs/libmythtv/signalmonitor.h (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/signalmonitor.h (.../branches/release-0-19-fixes) (revision 10931) @@ -7,6 +7,10 @@ // C headers #include +// C++ headers +#include +using namespace std; + // Qt headers #include #include @@ -125,7 +129,8 @@ * Defaults to 25 milliseconds. * \param msec Milliseconds between signal monitoring events. */ - void SetUpdateRate(int msec) { update_rate = msec; } + void SetUpdateRate(int msec) + { update_rate = max(msec, (int)minimum_update_rate); } public slots: virtual void deleteLater(void); @@ -164,6 +169,7 @@ int capturecardnum; uint flags; int update_rate; + uint minimum_update_rate; bool running; bool exit; bool update_done; Index: mythtv/libs/libmythtv/RingBuffer.h =================================================================== --- mythtv/libs/libmythtv/RingBuffer.h (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/RingBuffer.h (.../branches/release-0-19-fixes) (revision 10931) @@ -91,6 +91,7 @@ long long GetTotalReadPosition(void); long long SetAdjustFilesize(void); + void SetTimeout(bool fast) { oldfile = fast; } protected: static void *StartReader(void *type); Index: mythtv/libs/libmythtv/dvbtypes.cpp =================================================================== --- mythtv/libs/libmythtv/dvbtypes.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/dvbtypes.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -202,7 +202,7 @@ { {"TRANSMISSION_MODE_AUTO",TRANSMISSION_MODE_AUTO}, {"TRANSMISSION_MODE_2K",TRANSMISSION_MODE_2K}, - {"TRANSMISSION_MODE_8K",TRANSMISSION_MODE_2K}, + {"TRANSMISSION_MODE_8K",TRANSMISSION_MODE_8K}, {NULL,TRANSMISSION_MODE_AUTO}, }; @@ -210,7 +210,7 @@ { {"999",TRANSMISSION_MODE_AUTO}, {"2",TRANSMISSION_MODE_2K}, - {"8",TRANSMISSION_MODE_2K}, + {"8",TRANSMISSION_MODE_8K}, {NULL,TRANSMISSION_MODE_AUTO}, }; @@ -218,7 +218,7 @@ { {"auto",TRANSMISSION_MODE_AUTO}, {"2",TRANSMISSION_MODE_2K}, - {"8",TRANSMISSION_MODE_2K}, + {"8",TRANSMISSION_MODE_8K}, {NULL,TRANSMISSION_MODE_AUTO}, }; Index: mythtv/libs/libmythtv/mpegrecorder.cpp =================================================================== --- mythtv/libs/libmythtv/mpegrecorder.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/mpegrecorder.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -363,9 +363,9 @@ if (ioctl(chanfd, VIDIOC_S_CTRL, &ctrl) < 0) { - cerr << "Error setting codec params\n"; + cerr << "Warning, unable to set recording volume\n"; + cerr << "This is normal if you have an AVerMedia M179 card.\n"; perror("VIDIOC_S_CTRL:"); - return false; } if (vbimode) { @@ -481,6 +481,9 @@ continue; case 0: printf("select timeout - ivtv driver has stopped responding\n"); + if(close(readfd) != 0) + perror("close"); + readfd = -1; // Force PVR card to be reopened on next iteration continue; default: break; } Index: mythtv/libs/libmythtv/ivtvdecoder.cpp =================================================================== --- mythtv/libs/libmythtv/ivtvdecoder.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/ivtvdecoder.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -270,7 +270,9 @@ GetNVP()->SetVideoParams(720 /*width*/, (ntsc) ? 480 : 576 /*height*/, (ntsc) ? 29.97f : 25.0f, keyframedist, 1.33); - + + fps = (ntsc) ? 29.97f : 25.0f; // save for later length calculations + ringBuffer->UpdateRawBitrate(8000); if (m_playbackinfo || livetv || watchingrecording) Index: mythtv/libs/libmythtv/dvbsignalmonitor.cpp =================================================================== --- mythtv/libs/libmythtv/dvbsignalmonitor.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/dvbsignalmonitor.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -100,6 +100,10 @@ #undef DVB_IO AddFlags(newflags); DBG_SM("constructor()", QString("initial flags 0x%1").arg(newflags,0,16)); + + minimum_update_rate = _channel->GetMinSignalMonitorDelay(); + if (minimum_update_rate > 30) + usleep(minimum_update_rate * 1000); } /** \fn DVBSignalMonitor::~DVBSignalMonitor() @@ -348,8 +352,8 @@ len += remainder; remainder = GetStreamData()->ProcessData(buffer, len); - if (remainder > 0) // leftover bytes - memmove(buffer, &(buffer[buffer_size - remainder]), remainder); + if (remainder > 0 && (len > remainder)) // leftover bytes + memmove(buffer, &(buffer[len - remainder]), remainder); } VERBOSE(VB_CHANNEL, LOC + "RunTableMonitorTS(): " + "shutdown"); Index: mythtv/libs/libmythtv/tv_rec.cpp =================================================================== --- mythtv/libs/libmythtv/tv_rec.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/tv_rec.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -130,6 +130,11 @@ // RingBuffer info ringBuffer(NULL), rbFilePrefix(""), rbFileExt("mpg") { + // Retune stuff + retune_timer = new TuningTimer(); + retune_timer->setTimeout(10000); + retune_timer->start(); + retune_requests = 0; } /** \fn TVRec::Init() @@ -3221,6 +3226,8 @@ */ void TVRec::HandleTuning(void) { + bool handle_done = false; + if (tuningRequests.size()) { const TuningRequest *request = &tuningRequests.front(); @@ -3232,7 +3239,12 @@ kFlagEITScan|kFlagAntennaAdjust)) { if (!recorder) + { TuningFrequency(*request); + retune_timer->restart(); + retune_timer->addMSecs(1); + retune_requests = 0; + } else SetFlags(kFlagWaitingForRecPause); } @@ -3261,15 +3273,29 @@ if (HasFlags(kFlagWaitingForSignal)) { if (!TuningSignalCheck()) - return; + handle_done = true; } if (HasFlags(kFlagWaitingForSIParser)) { if (!TuningPMTCheck()) - return; + handle_done = true; } +#ifdef USING_DVB + // Just because we have signal, we may not have the right transponder + if ((HasFlags(kFlagWaitingForSignal) || + HasFlags(kFlagWaitingForSIParser)) && + (!retune_timer->elapsed() && (retune_requests < 30))) + { + RetuneChannel(); + retune_requests++; + } +#endif // USING_DVB + + if (handle_done) + return; + if (HasFlags(kFlagNeedToStartRecorder)) { if (recorder) @@ -3354,6 +3380,19 @@ ClearFlags(kFlagPendingActions); } +/** \fn TVRec::RetuneChannel(void) + * \brief Retunes a DVB channel + * \return DVBChannel::Retune() or false if ifndef USING_DVB + */ +bool TVRec::RetuneChannel(void) +{ +#ifdef USING_DVB + if (GetDVBChannel()) + return GetDVBChannel()->Retune(); +#endif // USING_DVB + return false; +} + /** \fn TVRec::TuningFrequency(const TuningRequest&) * \brief Performs initial tuning required for any tuning event. * Index: mythtv/libs/libmythtv/videooutbase.h =================================================================== --- mythtv/libs/libmythtv/videooutbase.h (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/videooutbase.h (.../branches/release-0-19-fixes) (revision 10931) @@ -256,6 +256,8 @@ /// onto the queue of frames ready for decoding onto. virtual void DiscardFrames(bool kf) { vbuffers.DiscardFrames(kf); } + virtual void CheckFrameStates(void) { } + /// \bug not implemented correctly. vpos is not updated. VideoFrame *GetLastDecodedFrame(void) { return vbuffers.GetLastDecodedFrame(); } Index: mythtv/libs/libmythtv/osdimagecache.cpp =================================================================== --- mythtv/libs/libmythtv/osdimagecache.cpp (.../tags/release-0-19) (revision 0) +++ mythtv/libs/libmythtv/osdimagecache.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -0,0 +1,296 @@ +// -*- Mode: c++ -*- +/** OSDImageCache + * Copyright (c) 2006 by Pekka Jääskeläinen, Daniel Thor Kristjansson + * Distributed as part of MythTV under GPL v2 and later. + */ + +// POSIX headers +#include + +// Qt headers +#include +#include +#include +#include +#include + +// MythTV headers +#include "mythcontext.h" +#include "osdimagecache.h" + +// Print statistics of OSD image access in the destructor of OSDImageCache +//#define PRINT_OSD_IMAGE_CACHE_STATS + +#define LOC QString("OSDImgCache: ") +#define LOC_ERR QString("OSDImgCache, Error: ") + +uint OSDImageCache::kMaximumMemoryCacheSize = 5 * 1024 * 1024; + +/** \fn OSDImageCacheValue::OSDImageCacheValue(unsigned char*,unsigned char*,unsighed char*,unsigned char*,unsighed char*, QRect) + * \brief The main constructor that takes the image data as arguments. + * + * The image data becomes property of the OSDImageCacheValue + * and will be deleted by it. + */ +OSDImageCacheValue::OSDImageCacheValue( + QString cacheKey, + unsigned char *yuv, unsigned char *ybuffer, + unsigned char *ubuffer, unsigned char *vbuffer, + unsigned char *alpha, QRect imagesize) : + m_yuv(yuv), m_ybuffer(ybuffer), + m_ubuffer(ubuffer), m_vbuffer(vbuffer), + m_alpha(alpha), m_imagesize(imagesize), + m_cacheKey(QDeepCopy(cacheKey)) +{ + uint yuv_size = m_imagesize.width() * m_imagesize.height() * 3 / 2; + m_size_in_bytes = + (sizeof(OSDImageCacheValue)) + yuv_size + + (m_imagesize.width() * m_imagesize.height()); +} + +/** \fn OSDImageCacheValue::~OSDImageCacheValue() + * \brief Destructor, frees the cached bitmaps. + */ +OSDImageCacheValue::~OSDImageCacheValue() +{ + delete [] m_yuv; + m_yuv = NULL; + delete [] m_alpha; + m_alpha = NULL; +} + +/** \fn OSDImageCache::OSDImageCache() + * \brief Constructor, initializes the internal cache structures. + */ +OSDImageCache::OSDImageCache() : + m_cacheLock(true), m_imageCache(kMaximumMemoryCacheSize, 50), + m_memHits(0), m_diskHits(0), m_misses(0) +{ + // When the cache gets too large, items are + // automatically deleted from it in LRU order. + m_imageCache.setAutoDelete(true); +} + +/** \fn OSDImageCache::~OSDImageCache() + * \brief Destructor, frees all cached OSD images. + */ +OSDImageCache::~OSDImageCache() +{ +#ifdef PRINT_OSD_IMAGE_CACHE_STATS + int totalAccess = m_memHits + m_diskHits + m_misses; + if (totalAccess == 0) + return; + +#define LOG_PREFIX "OSDImageCache: " + VERBOSE(VB_IMPORTANT, LOC << " Statistics: " << endl + << LOG_PREFIX << m_imageCache.totalCost() << " bytes in cache\n" + << LOG_PREFIX << " memory hits: " + << m_memHits << ", " << m_memHits*100.0/totalAccess << "%\n" + << LOG_PREFIX << " disk hits: " + << m_diskHits << ", " << m_diskHits*100.0/totalAccess << "%\n" + << LOG_PREFIX << " misses: " + << m_misses << ", " << m_misses*100.0/totalAccess << "%"); +#undef LOC_PREFIX +#endif + Reset(); +} + +/** \fn OSDImageCache::Contains(const QString&,bool) + * \brief Returns true if cached OSD image was found in the cache. + * + * \param key The key for this image. + * \param useFile If true, also look from the disk cache. + */ +bool OSDImageCache::Contains(const QString &key, bool useFile) const +{ + QMutexLocker locker(&m_cacheLock); + + if (m_imageCache.find(key) != NULL) + return true; + + if (!useFile) + return false; + + return InFileCache(key); +} + +bool OSDImageCache::InFileCache(const QString &key) const +{ + // check if cache file exists + QDir dir(MythContext::GetConfDir() + "/osdcache/"); + QFileInfo cFile(dir.path() + "/" + key); + if (!cFile.exists() || !cFile.isReadable()) + return false; + + // check if backing file exists + QString orig = ExtractOriginal(key); + if (orig.isEmpty()) + return false; + + QFileInfo oFile(orig); + if (!oFile.exists()) + { + VERBOSE(VB_IMPORTANT, LOC + QString("Can't find '%1'").arg(orig)); + return false; + } + + // if cache file is older than backing file, delete cache file + if (cFile.lastModified() < oFile.lastModified()) + { + cFile.dir().remove(cFile.baseName(true)); + return false; + } + + return true; +} + +/** \fn OSDImageCache::Get(const QString&,bool) + * \brief Returns OSD image data from cache. + * + * This also removes the image from the cache so it won't be deleted + * while in use. The deletion of the taken item becomes responsibility + * of the client. Returns NULL if item with the given key is not found. + * + * \param key The key for this image. + * \param useFile If true, also check the disk cache. + */ +OSDImageCacheValue *OSDImageCache::Get(const QString &key, bool useFile) +{ + QMutexLocker locker(&m_cacheLock); + OSDImageCacheValue* item = m_imageCache.find(key); + if (item) + { + m_memHits++; + return m_imageCache.take(key); + } + + if (!useFile || !InFileCache(key)) + { + m_misses++; + return NULL; + } + + QDir dir(MythContext::GetConfDir() + "/osdcache/"); + QFile cacheFile(dir.path() + "/" + key); + cacheFile.open(IO_ReadOnly); + uint32_t imwidth = 0; + uint32_t imheight = 0; + + QDataStream stream(&cacheFile); + stream >> imwidth >> imheight; + + uint yuv_size = imwidth * imheight * 3 / 2; + uint tot_size = (sizeof(imwidth) * 2) + yuv_size + (imwidth * imheight); + + if (cacheFile.size() != tot_size) + { + VERBOSE(VB_IMPORTANT, LOC_ERR + key + " wrong cache file size!" + << cacheFile.size() << " != " << tot_size); + return NULL; + } + + unsigned char *yuv = new unsigned char[yuv_size]; + unsigned char *alpha = new unsigned char[imwidth * imheight]; + stream.readRawBytes((char*)yuv, yuv_size); + stream.readRawBytes((char*)alpha, imwidth * imheight); + cacheFile.close(); + + OSDImageCacheValue* value = + new OSDImageCacheValue( + key, + yuv, yuv, + yuv + (imwidth * imheight), + yuv + (imwidth * imheight * 5 / 4), + alpha, QRect(0, 0, imwidth, imheight)); + + m_diskHits++; + return value; +} + +/** \fn OSDImageCache::Insert(OSDImageCacheValue*) + * \brief Inserts OSD image data to memory cache. + * + * The item becomes property of the OSDImageCache and may be + * deleted any time by it. + * + * \param value The cache item. + */ +void OSDImageCache::Insert(OSDImageCacheValue *value) +{ + if (!value) + return; + + QMutexLocker locker(&m_cacheLock); + if (!m_imageCache.insert(value->GetKey(), value, value->GetSize())) + { + VERBOSE(VB_IMPORTANT, + LOC_ERR + QString("inserting image to memory cache failed")); + } +} + + +/** \fn OSDImageCache::SaveToDisk(const OSDImageCacheValue*) + * \brief Saves OSD image data to disk cache. + * + * Item is not written to the memory cache, i.e., it stays as + * property of the client. + * + * \param value The cached OSD image to save. + */ +void OSDImageCache::SaveToDisk(const OSDImageCacheValue *value) +{ + if (InFileCache(value->GetKey())) + return; + + QDir dir(MythContext::GetConfDir() + "/osdcache/"); + if (!dir.exists() && !dir.mkdir(dir.path())) + { + VERBOSE(VB_IMPORTANT, LOC_ERR + "Creating osdcache directory failed."); + return; + } + + QFile cacheFile(dir.path() + "/" + value->GetKey()); + if (!cacheFile.open(IO_WriteOnly | IO_Truncate)) + { + VERBOSE(VB_IMPORTANT, LOC_ERR + "Creating osdcache file failed."); + return; + } + + uint32_t imwidth = value->m_imagesize.width(); + uint32_t imheight = value->m_imagesize.height(); + uint yuv_size = imwidth * imheight * 3 / 2; + + QDataStream stream(&cacheFile); + stream << imwidth << imheight; + stream.writeRawBytes((const char*)value->m_yuv, yuv_size); + stream.writeRawBytes((const char*)value->m_alpha, imwidth * imheight); + cacheFile.close(); +} + +/** \fn OSDImageCache::CreateKey(const QString&,float,float,int,int) + * \brief Generates a cache key from the given OSD image parameters. + * + * The returned key is a string that can be safely used as a file name. + */ +QString OSDImageCache::CreateKey(const QString &filename, float wmult, + float hmult, int scalew, int scaleh) +{ + QString tmp = filename; + return QString("cache_%1@%2_%3_%4_%5").arg(tmp.replace(QChar('/'), "+")) + .arg(wmult).arg(hmult).arg(scalew).arg(scaleh); +} + +QString OSDImageCache::ExtractOriginal(const QString &key) +{ + QString tmp0 = key.mid(6); + QString tmp1 = tmp0.left(tmp0.find("@")); + QString tmp2 = tmp1.replace(QChar('+'), "/"); + return tmp2; +} + +void OSDImageCache::Reset(void) +{ + QMutexLocker locker(&m_cacheLock); + // this also deletes the images due to setAutoDelete(true) + m_imageCache.clear(); +} Index: mythtv/libs/libmythtv/osd.cpp =================================================================== --- mythtv/libs/libmythtv/osd.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/osd.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -154,7 +154,8 @@ } OSDTypeCC *ccpage = new OSDTypeCC(name, ccfont, sub_xoff, sub_yoff, - sub_dispw, sub_disph); + sub_dispw, sub_disph, + wmult, hmult); container->AddType(ccpage); } @@ -517,7 +518,7 @@ } } - OSDTypeBox *box = new OSDTypeBox(name, area); + OSDTypeBox *box = new OSDTypeBox(name, area, wmult, hmult); container->AddType(box); } @@ -658,7 +659,7 @@ return; } - OSDTypeText *text = new OSDTypeText(name, ttffont, "", area); + OSDTypeText *text = new OSDTypeText(name, ttffont, "", area, wmult, hmult); container->AddType(text); text->SetMultiLine(multiline); @@ -875,7 +876,7 @@ QRect area = parseRect(getFirstText(info)); normalizeRect(area); - rects->AddPosition(area); + rects->AddPosition(area, wmult, hmult); } else { @@ -919,7 +920,7 @@ pos.setX((int)(pos.x() * wmult + xoffset)); pos.setY((int)(pos.y() * hmult + yoffset)); - image->AddPosition(pos); + image->AddPosition(pos, wmult, hmult); } else if (info.tagName() == "staticsize") { @@ -1925,7 +1926,7 @@ image = new OSDTypeImage(*editarrowright); } - image->SetPosition(QPoint(xpos, ypos)); + image->SetPosition(QPoint(xpos, ypos), wmult, hmult); set->AddType(image); set->Display(); Index: mythtv/libs/libmythtv/tv_rec.h =================================================================== --- mythtv/libs/libmythtv/tv_rec.h (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/tv_rec.h (.../branches/release-0-19-fixes) (revision 10931) @@ -13,6 +13,7 @@ #include "mythdeque.h" #include "programinfo.h" #include "tv.h" +#include "util.h" class QSocket; class NuppelVideoRecorder; @@ -48,6 +49,30 @@ BROWSE_FAVORITE ///< Fetch information on the next favorite channel } BrowseDirections; +class TuningTimer +{ + public: + TuningTimer() {} + + void setTimeout(long t) { _timeout = t; } + long timeout(void) { return _timeout; } + void start() { t_timer.start(); } + int restart() { int ret = elapsed(); + t_timer.restart(); + return ret; + } + int elapsed() { int ret = t_timer.elapsed(); + if (ret > _timeout) { ret = 0; t_timer.restart(); } + return ret; + } + + void addMSecs(int ms) { t_timer.addMSecs(ms); } + + private: + QTime t_timer; + long _timeout; +}; + class GeneralDBOptions { public: @@ -275,6 +300,7 @@ bool TuningPMTCheck(void); void TuningNewRecorder(void); void TuningRestartRecorder(void); + bool RetuneChannel(void); void HandleStateChange(void); void ChangeState(TVState nextState); @@ -362,6 +388,10 @@ QString rbFilePrefix; QString rbFileExt; + // Retune stuff + TuningTimer *retune_timer; + int retune_requests; + public: static const uint kEITScanStartTimeout; static const uint kSignalMonitoringRate; Index: mythtv/libs/libmythtv/videobuffers.h =================================================================== --- mythtv/libs/libmythtv/videobuffers.h (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/videobuffers.h (.../branches/release-0-19-fixes) (revision 10931) @@ -40,6 +40,7 @@ kVideoBuffer_used = 0x00000004, kVideoBuffer_pause = 0x00000008, kVideoBuffer_displayed = 0x00000010, + kVideoBuffer_decode = 0x00000020, kVideoBuffer_all = 0x0000001F, }; @@ -159,7 +160,6 @@ uint vpos; mutable QMutex global_lock; - QMutex inheritence_lock; bool use_frame_locks; QMutex frame_lock; Index: mythtv/libs/libmythtv/dvbconfparser.cpp =================================================================== --- mythtv/libs/libmythtv/dvbconfparser.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/dvbconfparser.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -193,10 +193,10 @@ QStringList::Iterator end = tokens.end(); if (i != end) c.name = *i++; else return false; - if (i != end) c.frequency = (*i++).toInt(); else return false; + if (i != end) c.frequency = (*i++).toUInt()*1000; else return false; if (i == end || !c.polarity.parseConf(*i++)) return false; if (i == end ) return false; else i++; //Sat num - if (i != end) c.symbolrate = (*i++).toInt(); else return false; + if (i != end) c.symbolrate = (*i++).toUInt()*1000; else return false; if (i == end ) return false; else i++; if (i == end ) return false; else i++; if (i != end) c.serviceid = (*i++).toInt(); else return false; Index: mythtv/libs/libmythtv/pchdtvsignalmonitor.cpp =================================================================== --- mythtv/libs/libmythtv/pchdtvsignalmonitor.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/pchdtvsignalmonitor.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -108,8 +108,8 @@ len += remainder; remainder = GetStreamData()->ProcessData(buffer, len); - if (remainder > 0) // leftover bytes - memmove(buffer, &(buffer[buffer_size - remainder]), remainder); + if (remainder > 0 && (len > remainder)) // leftover bytes + memmove(buffer, &(buffer[len - remainder]), remainder); } DBG_SM("RunTableMonitor()", "end"); } Index: mythtv/libs/libmythtv/videobuffers.cpp =================================================================== --- mythtv/libs/libmythtv/videobuffers.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmythtv/videobuffers.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -84,7 +84,7 @@ : numbuffers(0), needfreeframes(0), needprebufferframes(0), needprebufferframes_normal(0), needprebufferframes_small(0), keepprebufferframes(0), need_extra_for_pause(false), rpos(0), vpos(0), - global_lock(true), inheritence_lock(false), use_frame_locks(true), + global_lock(true), use_frame_locks(true), frame_lock(true) { } @@ -125,6 +125,8 @@ { global_lock.lock(); + Reset(); + uint numcreate = numdecode + ((extra_for_pause) ? 1 : 0); // make a big reservation, so that things that depend on @@ -409,6 +411,8 @@ q = &limbo; else if (type == kVideoBuffer_pause) q = &pause; + else if (type == kVideoBuffer_decode) + q = &decode; global_lock.unlock(); return q; @@ -429,6 +433,8 @@ q = &limbo; else if (type == kVideoBuffer_pause) q = &pause; + else if (type == kVideoBuffer_decode) + q = &decode; global_lock.unlock(); return q; @@ -503,6 +509,8 @@ limbo.remove(frame); if ((type & kVideoBuffer_pause) == kVideoBuffer_pause) pause.remove(frame); + if ((type & kVideoBuffer_decode) == kVideoBuffer_decode) + decode.remove(frame); global_lock.unlock(); } } @@ -857,7 +865,7 @@ { (void)frame; #ifdef USING_XVMC - inheritence_lock.lock(); + global_lock.lock(); frame_map_t::iterator it = parents.find(frame); if (it == parents.end()) @@ -902,18 +910,18 @@ children[*it].push_back((VideoFrame*)frame); } - inheritence_lock.unlock(); + global_lock.unlock(); #endif // USING_XVMC } void VideoBuffers::RemoveInheritence(const VideoFrame *frame) { - inheritence_lock.lock(); + global_lock.lock(); frame_map_t::iterator it = parents.find(frame); if (it == parents.end()) { - inheritence_lock.unlock(); + global_lock.unlock(); return; } @@ -945,7 +953,7 @@ .arg(i).arg(DebugString(*pit))); } - inheritence_lock.unlock(); + global_lock.unlock(); } frame_queue_t VideoBuffers::Children(const VideoFrame *frame) Index: mythtv/libs/libavformat/aviobuf.c =================================================================== --- mythtv/libs/libavformat/aviobuf.c (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libavformat/aviobuf.c (.../branches/release-0-19-fixes) (revision 10931) @@ -164,7 +164,13 @@ void url_fskip(ByteIOContext *s, offset_t offset) { - url_fseek(s, offset, SEEK_CUR); + if (offset < 16384) + { + static unsigned char fskipbuf[16384]; + get_buffer(s, fskipbuf, offset); + } + else + url_fseek(s, offset, SEEK_CUR); } offset_t url_ftell(ByteIOContext *s) Index: mythtv/libs/libmyth/lcddevice.cpp =================================================================== --- mythtv/libs/libmyth/lcddevice.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmyth/lcddevice.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -150,7 +150,7 @@ if (!connected) { - QTextStream os(socket); + QTextStream os(socket->socketDevice()); int count = 0; do @@ -213,7 +213,7 @@ return; } - QTextStream os(socket); + QTextStream os(socket->socketDevice()); last_command = someText; @@ -224,7 +224,7 @@ #endif // Just stream the text out the socket - os << someText << "\n" << flush; + os << someText << "\n"; } else { Index: mythtv/libs/libmyth/audiooutputca.cpp =================================================================== --- mythtv/libs/libmyth/audiooutputca.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmyth/audiooutputca.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -21,6 +21,7 @@ #include "mythcontext.h" #include "audiooutputca.h" +#include "config.h" // this holds Core Audio member variables struct CoreAudioData { @@ -107,8 +108,10 @@ bzero(&conv_in_desc, sizeof(AudioStreamBasicDescription)); conv_in_desc.mSampleRate = audio_samplerate; conv_in_desc.mFormatID = kAudioFormatLinearPCM; - conv_in_desc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger - | kLinearPCMFormatFlagIsBigEndian; + conv_in_desc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; +#ifdef WORDS_BIGENDIAN + conv_in_desc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; +#endif conv_in_desc.mBytesPerPacket = audio_bytes_per_sample; conv_in_desc.mFramesPerPacket = 1; conv_in_desc.mBytesPerFrame = audio_bytes_per_sample; Index: mythtv/libs/libmyth/util.cpp =================================================================== --- mythtv/libs/libmyth/util.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmyth/util.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -1006,16 +1006,20 @@ long long freespace = -1; QCString cstr = file_on_disk.local8Bit(); - if (statfs(cstr, &statbuf) == 0) + total = used = -1; + + // there are cases where statfs will return 0 (good), but f_blocks and + // others are invalid and set to 0 (such as when an automounted directory + // is not mounted but still visible because --ghost was used), + // so check to make sure we can have a total size > 0 + if ((statfs(cstr, &statbuf) == 0) && + (statbuf.f_blocks > 0) && + (statbuf.f_bsize > 0)) { freespace = statbuf.f_bsize * (statbuf.f_bavail >> 10); total = statbuf.f_bsize * (statbuf.f_blocks >> 10); used = total - freespace; } - else - { - freespace = total = used = -1; - } return freespace; } Index: mythtv/libs/libmyth/mythdialogs.cpp =================================================================== --- mythtv/libs/libmyth/mythdialogs.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmyth/mythdialogs.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -2617,6 +2617,7 @@ password_editor->setEchoMode(QLineEdit::Password); password_editor->setGeometry(textWidth + 20,10,135,30); password_editor->setBackgroundOrigin(ParentOrigin); + password_editor->setAllowVirtualKeyboard(false); connect(password_editor, SIGNAL(textChanged(const QString &)), this, SLOT(checkPassword(const QString &))); Index: mythtv/libs/libmyth/mythwidgets.cpp =================================================================== --- mythtv/libs/libmyth/mythwidgets.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmyth/mythwidgets.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -353,7 +353,8 @@ (e->key() == Qt::Key_Enter) || (e->key() == Qt::Key_Return))) { - if (gContext->GetNumSetting("UseVirtualKeyboard", 1) == 1) + if ((allowVirtualKeyboard) && + (gContext->GetNumSetting("UseVirtualKeyboard", 1) == 1)) { popup = new VirtualKeyboard(gContext->GetMainWindow(), this); gContext->GetMainWindow()->detach(popup); @@ -726,10 +727,11 @@ QWidget::focusNextPrevChild(true); emit tryingToLooseFocus(true); } - else if (action == "SELECT" && - (e->text().isNull() || - (e->key() == Qt::Key_Enter) || - (e->key() == Qt::Key_Return))) + else if ((action == "SELECT") && + (!active_cycle) && + ((e->text().isNull()) || + (e->key() == Qt::Key_Enter) || + (e->key() == Qt::Key_Return))) { if (gContext->GetNumSetting("UseVirtualKeyboard", 1) == 1) { @@ -749,7 +751,7 @@ if (handled) return; - if (!handled && popup && popup->isShown()) + if (popup && popup->isShown()) { endCycle(); QTextEdit::keyPressEvent(e); Index: mythtv/libs/libmyth/remotefile.h =================================================================== --- mythtv/libs/libmyth/remotefile.h (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmyth/remotefile.h (.../branches/release-0-19-fixes) (revision 10931) @@ -27,6 +27,8 @@ long long GetFileSize(void); + void SetTimeout(bool fast); + private: QSocketDevice *openSocket(bool control); @@ -43,6 +45,7 @@ QMutex lock; long long filesize; + bool timeoutisfast; }; #endif Index: mythtv/libs/libmyth/mythwidgets.h =================================================================== --- mythtv/libs/libmyth/mythwidgets.h (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmyth/mythwidgets.h (.../branches/release-0-19-fixes) (revision 10931) @@ -122,17 +122,21 @@ Q_OBJECT public: MythLineEdit(QWidget *parent=NULL, const char* widgetName=0) : - QLineEdit(parent, widgetName) { rw = true; Init(); }; + QLineEdit(parent, widgetName) + { rw = true; allowVirtualKeyboard = true; Init(); }; MythLineEdit(const QString& contents, QWidget *parent=NULL, const char* widgetName=0) : - QLineEdit(contents, parent, widgetName) { rw = true; Init(); }; + QLineEdit(contents, parent, widgetName) + { rw = true; allowVirtualKeyboard = true; Init(); }; virtual ~MythLineEdit(); void setHelpText(QString help) { helptext = help; }; void setRW(bool readwrite = true) { rw = readwrite; }; void setRO() { rw = false; }; + void setAllowVirtualKeyboard(bool allowKbd = true) + { allowVirtualKeyboard = allowKbd; } void setPopupPosition(PopupPosition pos) { popupPosition = pos; } PopupPosition getPopupPosition(void) { return popupPosition; } @@ -154,6 +158,7 @@ VirtualKeyboard *popup; QString helptext; bool rw; + bool allowVirtualKeyboard; PopupPosition popupPosition; }; Index: mythtv/libs/libmyth/mythcontext.cpp =================================================================== --- mythtv/libs/libmyth/mythcontext.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmyth/mythcontext.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -2621,9 +2621,13 @@ d->LoadLogSettings(); if (d->m_logenable == 1) { + QString fullMsg = message; + if (!details.isEmpty()) + fullMsg += ": " + details; + if (message.left(21) != "Last message repeated") { - if (message == d->lastLogStrings[module]) + if (fullMsg == d->lastLogStrings[module]) { d->lastLogCounts[module] += 1; return; @@ -2639,7 +2643,7 @@ } d->lastLogCounts[module] = 0; - d->lastLogStrings[module] = message; + d->lastLogStrings[module] = fullMsg; } } @@ -2693,7 +2697,7 @@ } if (priority <= d->m_logprintlevel) - VERBOSE(VB_IMPORTANT, module + ": " + message); + VERBOSE(VB_IMPORTANT, module + ": " + fullMsg); } } Index: mythtv/libs/libmyth/remotefile.cpp =================================================================== --- mythtv/libs/libmyth/remotefile.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libmyth/remotefile.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -15,6 +15,7 @@ path = url; readposition = 0; filesize = -1; + timeoutisfast = false; query = "QUERY_FILETRANSFER %1"; @@ -295,4 +296,34 @@ Read(data.data(), filesize); return true; -} +} + +void RemoteFile::SetTimeout(bool fast) +{ + if (timeoutisfast == fast) + return; + + if (!sock) + { + VERBOSE(VB_NETWORK, "RemoteFile::Seek(): Called with no socket"); + return; + } + + if (!sock->isOpen() || sock->error()) + return; + + if (!controlSock->isOpen() || controlSock->error()) + return; + + QStringList strlist = QString(query).arg(recordernum); + strlist << "SET_TIMEOUT"; + strlist << QString::number((int)fast); + + lock.lock(); + WriteStringList(controlSock, strlist); + ReadStringList(controlSock, strlist); + lock.unlock(); + + timeoutisfast = fast; +} + Index: mythtv/libs/libavcodec/libavcodec.pro =================================================================== --- mythtv/libs/libavcodec/libavcodec.pro (.../tags/release-0-19) (revision 10931) +++ mythtv/libs/libavcodec/libavcodec.pro (.../branches/release-0-19-fixes) (revision 10931) @@ -430,4 +430,5 @@ LIBS += -lz QMAKE_LFLAGS_SHLIB += -single_module QMAKE_LFLAGS_SHLIB += -seg1addr 0xC3000000 + QMAKE_LFLAGS_SHLIB += -read_only_relocs warning } Index: mythtv/programs/mythfrontend/playbackbox.cpp =================================================================== --- mythtv/programs/mythfrontend/playbackbox.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/programs/mythfrontend/playbackbox.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -140,6 +141,7 @@ // Main Recording List support fillListTimer(new QTimer(this)), connected(false), titleIndex(0), progIndex(0), + progsInDB(0), // Other state curitem(NULL), delitem(NULL), lastProgram(NULL), @@ -261,7 +263,9 @@ setNoErase(); gContext->addListener(this); - if (!recGroupPassword.isEmpty() || (titleList.count() <= 1) || initialFilt) + if ((!recGroupPassword.isEmpty()) || + ((titleList.count() <= 1) && (progsInDB > 0)) || + (initialFilt)) showRecGroupChooser(); gContext->addCurrentLocation((type == Delete)? "DeleteBox":"PlaybackBox"); @@ -890,9 +894,13 @@ !playingSomething) { QSize size = drawVideoBounds.size(); + float saspect = ((float)size.width()) / ((float)size.height()); + float vaspect = previewVideoNVP->GetVideoAspect(); + size.setHeight((int) ceil(size.height() * (saspect / vaspect))); + size.setHeight(((size.height() + 7) / 8) * 8); + size.setWidth( ((size.width() + 7) / 8) * 8); const QImage &img = previewVideoNVP->GetARGBFrame(size); - uint xoff = max((size.width() - drawVideoBounds.width()) / 2, 0); - p->drawImage(drawVideoBounds.x() + xoff, drawVideoBounds.y(), img); + p->drawImage(drawVideoBounds.x(), drawVideoBounds.y(), img); } /* have we timed out waiting for nvp to start? */ @@ -1272,10 +1280,10 @@ paintSkipUpdate = false; update(drawTotalBounds); } + else if (arrowAccel) + showActionsSelected(); else if (curitem && curitem->availableStatus != asAvailable) showAvailablePopup(curitem); - else if (arrowAccel) - showActionsSelected(); } void PlaybackBox::cursorDown(bool page, bool newview) @@ -1380,6 +1388,7 @@ asCache[asKey] = p->availableStatus; } + progsInDB = 0; titleList.clear(); progLists.clear(); // Clear autoDelete for the "all" list since it will share the @@ -1402,6 +1411,7 @@ vector::iterator i = infoList->begin(); for ( ; i != infoList->end(); i++) { + progsInDB++; p = *i; if ((((p->recgroup == recGroup) || ((recGroup == "All Programs") && @@ -1886,7 +1896,8 @@ if (inTitle && haveGroupInfoSet) return; - if (curitem->availableStatus != asAvailable) + if ((curitem->availableStatus != asAvailable) && + (curitem->availableStatus != asFileNotFound)) showAvailablePopup(curitem); else showActions(curitem); @@ -2068,7 +2079,21 @@ delitem = new ProgramInfo(*toExp); - if (delitem->availableStatus != asAvailable) + if (fileExists(delitem) == false) + { + QString msg = + QString("PlaybackBox::showActions(): Error, %1 file not found") + .arg(delitem->pathname); + VERBOSE(VB_IMPORTANT, msg); + + ProgramInfo *tmpItem = findMatchingProg(delitem); + if (tmpItem) + { + tmpItem->availableStatus = asFileNotFound; + showFileNotFoundActionPopup(delitem); + } + } + else if (delitem->availableStatus != asAvailable) showAvailablePopup(delitem); else showActionPopup(delitem); @@ -2647,6 +2672,34 @@ expectingPopup = true; } +void PlaybackBox::showFileNotFoundActionPopup(ProgramInfo *program) +{ + if (!curitem || !program) + return; + + popup = new MythPopupBox(gContext->GetMainWindow(), drawPopupSolid, + drawPopupFgColor, drawPopupBgColor, + drawPopupSelColor, "action popup"); + + QString msg = QObject::tr("Recording Unavailable") + "\n"; + msg += QObject::tr("The file for this recording can " + "not be found") + "\n"; + + initPopup(popup, program, "", msg); + + QButton *detailsButton; + detailsButton = popup->addButton(tr("Show Program Details"), this, + SLOT(showProgramDetails())); + + popup->addButton(tr("Delete"), this, SLOT(askDelete())); + + popup->ShowPopup(this, SLOT(doCancel())); + + detailsButton->setFocus(); + + expectingPopup = true; +} + void PlaybackBox::initPopup(MythPopupBox *popup, ProgramInfo *program, QString message, QString message2) { @@ -4129,8 +4182,7 @@ if (!recGroupListBox) return; - QString item = - recGroupListBox->currentText().section('[', 0, 0).simplifyWhiteSpace(); + QString item = recGroupListBox->currentText().section(" [", 0, 0); if (item.left(5) == "-----") { @@ -4147,8 +4199,7 @@ void PlaybackBox::setGroupFilter(void) { - recGroup = - recGroupListBox->currentText().section('[', 0, 0).simplifyWhiteSpace(); + recGroup = recGroupListBox->currentText().section(" [", 0, 0); if (groupnameAsAllProg) groupDisplayName = recGroup; Index: mythtv/programs/mythfrontend/customrecord.cpp =================================================================== --- mythtv/programs/mythfrontend/customrecord.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/programs/mythfrontend/customrecord.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -149,7 +149,7 @@ m_cfrom << ""; m_csql << "program.stars >= 0.75 "; - m_clause->insertItem(tr("Person named in the credits")); + m_clause->insertItem(tr("Person named in the credits (Data Direct)")); m_cfrom << ", people, credits"; m_csql << QString("people.name = 'Tom Hanks' \n" "AND credits.person = people.person \n" @@ -447,8 +447,8 @@ else { MSqlQuery query(MSqlQuery::InitCon()); - query.prepare(QString("SELECT NULL FROM program,channel %1 WHERE\n%2") - .arg(from).arg(desc)); + query.prepare(QString("SELECT NULL FROM (program,channel) " + "%1 WHERE\n%2").arg(from).arg(desc)); if (query.exec() && query.isActive()) { Index: mythtv/programs/mythfrontend/tv_schedule.xml =================================================================== --- mythtv/programs/mythfrontend/tv_schedule.xml (.../tags/release-0-19) (revision 10931) +++ mythtv/programs/mythfrontend/tv_schedule.xml (.../branches/release-0-19-fixes) (revision 10931) @@ -26,7 +26,7 @@ Guia EPG Guide - Dagskrá + Dagskrá Gids Guide ガイド Index: mythtv/programs/mythfrontend/playbackbox.h =================================================================== --- mythtv/programs/mythfrontend/playbackbox.h (.../tags/release-0-19) (revision 10931) +++ mythtv/programs/mythfrontend/playbackbox.h (.../branches/release-0-19-fixes) (revision 10931) @@ -237,6 +237,7 @@ void promptEndOfRecording(ProgramInfo *); void showDeletePopup(ProgramInfo *, deletePopupType); void showActionPopup(ProgramInfo *program); + void showFileNotFoundActionPopup(ProgramInfo *program); void initPopup(MythPopupBox *popup, ProgramInfo *program, QString message, QString message2); void cancelPopup(); @@ -337,6 +338,7 @@ int progIndex; ///< Index of selected item index on page QStringList titleList; ///< list of pages ProgramMap progLists; ///< lists of programs by page + int progsInDB; ///< total number of recordings in DB // Play List support QStringList playList; ///< list of selected items "play list" Index: mythtv/programs/mythfrontend/networkcontrol.cpp =================================================================== --- mythtv/programs/mythfrontend/networkcontrol.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/programs/mythfrontend/networkcontrol.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -469,7 +469,7 @@ message = "NETWORK_CONTROL SEEK BACKWARD"; else if (tokens[2].contains(QRegExp("^\\d\\d:\\d\\d:\\d\\d$"))) { - int hours = tokens[2].left(0).toInt(); + int hours = tokens[2].mid(0, 2).toInt(); int minutes = tokens[2].mid(3, 2).toInt(); int seconds = tokens[2].mid(6, 2).toInt(); message = QString("NETWORK_CONTROL SEEK POSITION %1") Index: mythtv/programs/mythtranscode/mpeg2fix.cpp =================================================================== --- mythtv/programs/mythtranscode/mpeg2fix.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/programs/mythtranscode/mpeg2fix.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -1776,6 +1776,7 @@ if (vFrame.count() && (file_end || vFrame.getLast()->isSequence)) { + MPEG2frame *seqFrame; if (ptsIncrement != vFrame.first()->mpeg2_seq.frame_period / 300) { VERBOSE(MPF_IMPORTANT, @@ -1786,6 +1787,11 @@ } displayFrame->toFirst(); + // since we might reorder the frames when coming out of a cutpoint + // me need to save the first frame here, as it is gauranteed to + // have a sequence header. + seqFrame = vFrame.current(); + while (vFrame.current() != vFrame.getLast()) { bool ptsorder_eq_dtsorder = false; @@ -1941,7 +1947,7 @@ if (! new_discard_state) { - AddSequence(markedFrame, vFrame.first()); + AddSequence(markedFrame, seqFrame); RenumberFrames(frame_pos + Lreorder.at(), - GetFrameNum(markedFrame)); } Index: mythtv/programs/mythcommflag/main.cpp =================================================================== --- mythtv/programs/mythcommflag/main.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/programs/mythcommflag/main.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -895,9 +895,6 @@ return COMMFLAG_EXIT_INVALID_CMDLINE; } - if (queueJobInstead) - return QueueCommFlagJob(chanid, starttime); - if (copyToCutlist) return CopySkipListToCutList(chanid, starttime); @@ -1009,7 +1006,10 @@ if ( allRecorded ) { - FlagCommercials(chanid, starttime); + if (queueJobInstead) + QueueCommFlagJob(chanid, starttime); + else + FlagCommercials(chanid, starttime); } else { @@ -1063,7 +1063,12 @@ if ((flagStatus == COMM_FLAG_NOT_FLAGGED) && (marksFound == 0)) - FlagCommercials(chanid, starttime); + { + if (queueJobInstead) + QueueCommFlagJob(chanid, starttime); + else + FlagCommercials(chanid, starttime); + } } } } Index: mythtv/programs/mythbackend/mainserver.cpp =================================================================== --- mythtv/programs/mythbackend/mainserver.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/programs/mythbackend/mainserver.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -1919,11 +1919,8 @@ if (m_sched) { if (table == "") m_sched->getAllPending(strList); else { - // We need a different connection from the scheduler proper - // DDCon exists, although it's designed for other purposes. - MSqlQueryInfo dbconn = MSqlQuery::DDCon(); - Scheduler *sched = new Scheduler(false, encoderList, - table, &dbconn, m_sched); + Scheduler *sched = new Scheduler(false, encoderList, + table, m_sched); sched->FillRecordListFromDB(recordid); sched->getAllPending(strList); delete sched; @@ -2940,6 +2937,12 @@ long long ret = ft->Seek(curpos, pos, whence); encodeLongLong(retlist, ret); } + else if (command == "SET_TIMEOUT") + { + bool fast = slist[2].toInt(); + ft->SetTimeout(fast); + retlist << "ok"; + } else { VERBOSE(VB_IMPORTANT, QString("Unknown command: %1").arg(command)); Index: mythtv/programs/mythbackend/scheduler.cpp =================================================================== --- mythtv/programs/mythbackend/scheduler.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/programs/mythbackend/scheduler.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -35,8 +35,7 @@ #define LOC_ERR QString("Scheduler, Error: ") Scheduler::Scheduler(bool runthread, QMap *tvList, - QString recordTbl, MSqlQueryInfo *databaseConnection, - Scheduler *master_sched) + QString recordTbl, Scheduler *master_sched) { hasconflicts = false; m_tvList = tvList; @@ -48,8 +47,11 @@ master_sched->getAllPending(&reclist); } - if (databaseConnection) dbConn = *databaseConnection; - else dbConn = MSqlQuery::SchedCon(); + // Only the master scheduler should use SchedCon() + if (runthread) + dbConn = MSqlQuery::SchedCon(); + else + dbConn = MSqlQuery::DDCon(); recordTable = recordTbl; @@ -1136,6 +1138,10 @@ if (reschedQueue.count()) { + // We might have been inactive for a long time, so make + // sure our DB connection is fresh before continuing. + dbConn = MSqlQuery::SchedCon(); + gettimeofday(&fillstart, NULL); QString msg; while (reschedQueue.count()) @@ -1827,10 +1833,10 @@ QString query = QString( "INSERT INTO recordmatch (recordid, chanid, starttime, manualid) " "SELECT RECTABLE.recordid, program.chanid, program.starttime, " -" IF(search = %1, recordid, 0) " -"FROM RECTABLE, program ").arg(kManualSearch) + fromclauses[clause] + QString( -" INNER JOIN channel ON (channel.chanid = program.chanid) " -"WHERE ") + whereclauses[clause] + QString(" AND channel.visible = 1 AND " +" IF(search = %1, recordid, 0) ").arg(kManualSearch) + QString( +"FROM (RECTABLE, program INNER JOIN channel " +" ON channel.chanid = program.chanid) ") + fromclauses[clause] + QString( +" WHERE ") + whereclauses[clause] + QString(" AND channel.visible = 1 AND " "((RECTABLE.type = %1 " // allrecord "OR RECTABLE.type = %2 " // findonerecord "OR RECTABLE.type = %3 " // finddailyrecord Index: mythtv/programs/mythbackend/housekeeper.cpp =================================================================== --- mythtv/programs/mythbackend/housekeeper.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/programs/mythbackend/housekeeper.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -138,7 +138,6 @@ while (1) { - VERBOSE(VB_IMPORTANT, "Running HouseKeeping"); gContext->LogEntry("mythbackend", LP_DEBUG, "Running housekeeping thread", ""); Index: mythtv/programs/mythbackend/scheduler.h =================================================================== --- mythtv/programs/mythbackend/scheduler.h (.../tags/release-0-19) (revision 10931) +++ mythtv/programs/mythbackend/scheduler.h (.../branches/release-0-19-fixes) (revision 10931) @@ -23,8 +23,7 @@ { public: Scheduler(bool runthread, QMap *tvList, - QString recordTbl = "record", MSqlQueryInfo *dbConnUse = NULL, - Scheduler *master_sched = NULL); + QString recordTbl = "record", Scheduler *master_sched = NULL); ~Scheduler(); void Reschedule(int recordid); Index: mythtv/programs/mythbackend/filetransfer.cpp =================================================================== --- mythtv/programs/mythbackend/filetransfer.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/programs/mythbackend/filetransfer.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -131,3 +131,9 @@ return size; } + +void FileTransfer::SetTimeout(bool fast) +{ + rbuffer->SetTimeout(fast); +} + Index: mythtv/programs/mythbackend/autoexpire.cpp =================================================================== --- mythtv/programs/mythbackend/autoexpire.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/programs/mythbackend/autoexpire.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -291,7 +291,8 @@ if ((availFreeKB = getDiskSpace(record_file_prefix, tKB, uKB)) < 0) { - QString msg = QString("ERROR: Could not calculate free space."); + QString msg = QString("ERROR: Could not calculate free space for %1.") + .arg(record_file_prefix); VERBOSE(VB_IMPORTANT, LOC + msg); gContext->LogEntry("mythbackend", LP_WARNING, "Autoexpire Recording", msg); Index: mythtv/programs/mythbackend/filetransfer.h =================================================================== --- mythtv/programs/mythbackend/filetransfer.h (.../tags/release-0-19) (revision 10931) +++ mythtv/programs/mythbackend/filetransfer.h (.../branches/release-0-19-fixes) (revision 10931) @@ -35,6 +35,8 @@ long long GetFileSize(void); + void SetTimeout(bool fast); + private: bool readthreadlive; QMutex readthreadLock; Index: mythtv/programs/mythtv/main.cpp =================================================================== --- mythtv/programs/mythtv/main.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/programs/mythtv/main.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -13,8 +13,6 @@ #include using namespace std; -MythContext *gContext; - static void *run_priv_thread(void *data) { (void)data; @@ -102,6 +100,9 @@ gContext->LoadQtConfig(); +#if defined(Q_OS_MACX) + // Mac OS X doesn't define the AudioOutputDevice setting +#else QString auddevice = gContext->GetSetting("AudioOutputDevice"); if (auddevice == "" || auddevice == QString::null) { @@ -109,6 +110,7 @@ "to run 'mythfrontend', not 'mythtv'."); return TV_EXIT_NO_AUDIO; } +#endif print_verbose_messages |= VB_PLAYBACK | VB_LIBAV;// | VB_AUDIO; @@ -132,6 +134,7 @@ ProgramInfo *pginfo = new ProgramInfo(); pginfo->endts = QDateTime::currentDateTime().addSecs(-180); pginfo->pathname = filename; + pginfo->isVideo = true; tv->Playback(pginfo); } Index: mythtv/programs/mythfilldatabase/filldata.cpp =================================================================== --- mythtv/programs/mythfilldatabase/filldata.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/programs/mythfilldatabase/filldata.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -337,7 +337,7 @@ MSqlQuery query(MSqlQuery::InitCon()); query.prepare("SELECT ch.chanid, nim.url " - "FROM channel ch, callsignnetworkmap csm " + "FROM (channel ch, callsignnetworkmap csm) " "RIGHT JOIN networkiconmap nim ON csm.network = nim.network " "WHERE ch.callsign = csm.callsign AND " "(icon = :NOICON OR icon = '') AND ch.sourceid = :SOURCEID"); @@ -2174,7 +2174,8 @@ 0 /*service id*/, major, minor, false /*use on air guide*/, false /*hidden*/, false /*hidden in guide*/, - freqid, localfile, (*i).tvformat)) + freqid, localfile, (*i).tvformat, + (*i).xmltvid)) { cout << "### " << endl; cout << "### Channel inserted" << endl; @@ -3851,7 +3852,6 @@ VERBOSE(VB_IMPORTANT, "Failed to fetch some program info"); gContext->LogEntry("mythfilldatabase", LP_WARNING, "Failed to fetch some program info", ""); - return FILLDB_EXIT_DB_ERROR; } else VERBOSE(VB_IMPORTANT, "Data fetching complete."); Index: mythtv/setup/backendsettings.cpp =================================================================== --- mythtv/setup/backendsettings.cpp (.../tags/release-0-19) (revision 10931) +++ mythtv/setup/backendsettings.cpp (.../branches/release-0-19-fixes) (revision 10931) @@ -1,6 +1,7 @@ #include #include "backendsettings.h" +#include "frequencies.h" #include "libmyth/mythcontext.h" #include "libmyth/settings.h" #include @@ -110,23 +111,10 @@ { GlobalComboBox *gc = new GlobalComboBox("FreqTable"); gc->setLabel(QObject::tr("Channel frequency table")); - gc->addSelection("us-cable"); - gc->addSelection("us-bcast"); - gc->addSelection("us-cable-hrc"); - gc->addSelection("us-cable-irc"); - gc->addSelection("japan-bcast"); - gc->addSelection("japan-cable"); - gc->addSelection("europe-west"); - gc->addSelection("europe-east"); - gc->addSelection("italy"); - gc->addSelection("newzealand"); - gc->addSelection("australia"); - gc->addSelection("ireland"); - gc->addSelection("france"); - gc->addSelection("china-bcast"); - gc->addSelection("southafrica"); - gc->addSelection("argentina"); - gc->addSelection("australia-optus"); + + for (uint i = 0; chanlists[i].name; i++) + gc->addSelection(chanlists[i].name); + gc->setHelpText(QObject::tr("Select the appropriate frequency table for " "your system. If you have an antenna, use a \"-bcast\" " "frequency."));