summaryrefslogtreecommitdiffstats
path: root/lib/class
diff options
context:
space:
mode:
authorPaul Arthur <flowerysong00@yahoo.com>2013-01-21 11:56:56 -0500
committerPaul Arthur <paul.arthur@flowerysong.com>2013-01-23 13:11:16 -0500
commit9340ff287c01eb9e5ebd0301dc9988f3536221dc (patch)
treecaabe3705c6d7bbb58bee4aa797d2750c8980712 /lib/class
parent37e09a642828a06a5f19a547729f40b7e2433772 (diff)
downloadampache-9340ff287c01eb9e5ebd0301dc9988f3536221dc.tar.gz
ampache-9340ff287c01eb9e5ebd0301dc9988f3536221dc.tar.bz2
ampache-9340ff287c01eb9e5ebd0301dc9988f3536221dc.zip
Rework transcoding
Remove some of the roundabout complexity that had built up. Push people toward using a single, flexible tool for most of their transcoding needs. Increase backend and configuration flexibility to support user-requested format changes (e.g. for an HTML5 player); this functionality is not yet exposed.
Diffstat (limited to 'lib/class')
-rw-r--r--lib/class/media.interface.php39
-rw-r--r--lib/class/radio.class.php20
-rw-r--r--lib/class/song.class.php133
-rw-r--r--lib/class/stream.class.php55
-rw-r--r--lib/class/video.class.php23
5 files changed, 110 insertions, 160 deletions
diff --git a/lib/class/media.interface.php b/lib/class/media.interface.php
index 617e12b5..b82b5ea8 100644
--- a/lib/class/media.interface.php
+++ b/lib/class/media.interface.php
@@ -1,8 +1,6 @@
<?php
/* vim:set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab: */
/**
- * media Interface
- *
*
* LICENSE: GNU General Public License, version 2 (GPLv2)
* Copyright (c) 2001 - 2011 Ampache.org All Rights Reserved
@@ -19,11 +17,6 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * @package Ampache
- * @copyright 2001 - 2011 Ampache.org
- * @license http://opensource.org/licenses/gpl-2.0 GPLv2
- * @link http://www.ampache.org/
*/
/**
@@ -32,51 +25,45 @@
* This defines how the media file classes should
* work, this lists all required functions and the expected
* input
- *
- * @package Ampache
- * @copyright 2001 - 2011 Ampache.org
- * @license http://opensource.org/licenses/gpl-2.0 GPLv2
- * @link http://www.ampache.org/
- * @see Video
- * @see Radio
- * @see Random
- * @see Song
*/
interface media {
/**
* format
*
- * @return
+ * Creates the gussied-up member variables for output
*/
public function format();
/**
- * native_stream
+ * get_stream_types
*
- * @return mixed
+ * Returns an array of strings; current types are 'native'
+ * and 'transcode'
*/
- public function native_stream();
+ public function get_stream_types();
/**
* play_url
*
- * @param int $oid ID
- * @return mixed
+ * Returns the url to stream the specified object
+ *
*/
public static function play_url($oid);
/**
- * stream_cmd
+ * get_transcode_settings
*
- * @return mixed
+ * Should only be called if 'transcode' was returned by get_stream_types
+ * Returns a raw transcode command for this item; the optional target
+ * parameter can be used to request a specific format instead of the
+ * default from the configuration file.
*/
- public function stream_cmd();
+ public function get_transcode_settings($target = null);
/**
* has_flag
*
- * @return mixed
*/
public function has_flag();
diff --git a/lib/class/radio.class.php b/lib/class/radio.class.php
index d4be4f76..a8d33ef3 100644
--- a/lib/class/radio.class.php
+++ b/lib/class/radio.class.php
@@ -188,13 +188,11 @@ class Radio extends database_object implements media {
} // delete
/**
- * native_stream
+ * get_stream_types
* This is needed by the media interface
*/
- public function native_stream() {
-
-
-
+ public function get_stream_types() {
+ return array('foreign');
} // native_stream
/**
@@ -220,13 +218,13 @@ class Radio extends database_object implements media {
} // has_flag
/**
- * stream_cmd
- * Needed by the media interface
+ * get_transcode_settings
+ *
+ * This will probably never be implemented
*/
- public function stream_cmd() {
-
-
- } // stream_cmd
+ public function get_transcode_settings() {
+ return false;
+ }
} //end of radio class
diff --git a/lib/class/song.class.php b/lib/class/song.class.php
index 70f6e881..ab38524a 100644
--- a/lib/class/song.class.php
+++ b/lib/class/song.class.php
@@ -62,11 +62,7 @@ class Song extends database_object implements media {
public $mbid; // MusicBrainz ID
/* Setting Variables */
- public $_transcoded = false;
- public $resampled = false;
public $_fake = false; // If this is a 'construct_from_array' object
- public $transcoded_from;
- private $_transcode_cmd;
/**
* Constructor
@@ -85,8 +81,9 @@ class Song extends database_object implements media {
foreach ($info as $key=>$value) {
$this->$key = $value;
}
- // Format the Type of the song
- $this->format_type();
+ $data = pathinfo($this->file);
+ $this->type = strtolower($data['extension']);
+ $this->mime = self::type_to_mime($this->type);
}
return true;
@@ -222,61 +219,53 @@ class Song extends database_object implements media {
} // fill_ext_info
/**
- * format_type
- * gets the type of song we are trying to
- * play, used to set mime headers and to trick
- * players into playing them correctly
+ * type_to_mime
+ *
+ * Returns the mime type for the specified file extension/type
*/
- public function format_type($override='') {
-
- // If we pass an override for downsampling or whatever then use it
- if (!empty($override)) {
- $this->type = $override;
- }
- else {
- $data = pathinfo($this->file);
- $this->type = strtolower($data['extension']);
- }
-
- switch ($this->type) {
+ public static function type_to_mime($type) {
+ // FIXME: This should really be done the other way around.
+ // Store the mime type in the database, and provide a function
+ // to make it a human-friendly type.
+ switch ($type) {
case 'spx':
case 'ogg':
- $this->mime = "application/ogg";
+ return 'application/ogg';
break;
case 'wma':
case 'asf':
- $this->mime = "audio/x-ms-wma";
+ return 'audio/x-ms-wma';
break;
case 'mp3':
case 'mpeg3':
- $this->mime = "audio/mpeg";
+ return 'audio/mpeg';
break;
case 'rm':
case 'ra':
- $this->mime = "audio/x-realaudio";
+ return 'audio/x-realaudio';
break;
case 'flac';
- $this->mime = "audio/x-flac";
+ return 'audio/x-flac';
break;
case 'wv':
- $this->mime = 'audio/x-wavpack';
+ return 'audio/x-wavpack';
break;
case 'aac':
case 'mp4':
case 'm4a':
- $this->mime = "audio/mp4";
+ return 'audio/mp4';
break;
case 'mpc':
- $this->mime = "audio/x-musepack";
+ return 'audio/x-musepack';
break;
default:
- $this->mime = "audio/mpeg";
+ return 'audio/mpeg';
break;
}
return true;
- } // format_type
+ }
/**
* get_album_name
@@ -923,63 +912,51 @@ class Song extends database_object implements media {
} // get_recently_played
- /**
- * native_stream
- * This returns true/false if this can be natively streamed
- */
- public function native_stream() {
-
- if ($this->_transcoded) { return false; }
-
- $conf_var = 'transcode_' . $this->type;
+ public function get_stream_types() {
+ $types = array();
+ $transcode = Config::get('transcode_' . $this->type);
- if (Config::get($conf_var)) {
- $this->set_transcode();
- return false;
+ if ($transcode != 'required') {
+ $types[] = 'native';
+ }
+ if (make_bool($transcode)) {
+ $types[] = 'transcode';
}
- return true;
-
- } // end native_stream
-
- /**
- * set_transcode
- *
- * We want to transcode, set up the variables correctly
- */
- public function set_transcode() {
- if ($this->_transcoded) { return; }
+ return $types;
+ } // end stream_types
- $conf_type = 'transcode_' . $this->type . '_target';
- $conf_cmd = 'transcode_cmd_' . $this->type;
+ public function get_transcode_settings($target = null) {
+ $source = $this->type;
- $this->_transcoded = true;
- $this->transcoded_from = $this->type;
- $this->_transcode_cmd = Config::get($conf_cmd);
- $this->format_type(Config::get($conf_type));
- if ($this->type == $this->transcoded_from) {
- $this->_resampled = true;
+ if ($target) {
+ debug_event('transcode', 'Explicit format request', 5);
+ }
+ else if ($target = Config::get('encode_target_' . $source)) {
+ debug_event('transcode', 'Defaulting to configured target format for ' . $source, 5);
+ }
+ else if ($target = Config::get('encode_target')) {
+ debug_event('transcode', 'Using default target format', 5);
+ }
+ else {
+ $target = $source;
+ debug_event('transcode', 'No default target for ' . $source . ', choosing to resample', 5);
}
- debug_event('transcode', 'Transcoding from ' .
- $this->transcoded_from . ' to ' . $this->type, 5);
- }
+ debug_event('transcode', 'Transcoding from ' . $source . ' to ' . $target, 5);
- /**
- * stream_cmd
- *
- * test if the song type streams natively and
- * if not returns a transcoding command from the config
- */
- public function stream_cmd() {
+ $cmd = Config::get('transcode_cmd_' . $source) ?: Config::get('transcode_cmd');
+ $args = Config::get('encode_args_' . $target);
- if ($this->native_stream()) {
- return null;
+ if (!$args) {
+ debug_event('transcode', 'Target format ' . $target . ' is not properly configured', 2);
+ return false;
}
-
- return $this->_transcode_cmd;
- } // end stream_cmd
+ debug_event('transcode', 'Command: ' . $cmd . ' Arguments: ' . $args, 5);
+ return array('format' => $target,
+ 'command' => $cmd . ' ' . $args);
+ }
} // end of song class
?>
diff --git a/lib/class/stream.class.php b/lib/class/stream.class.php
index 871f8394..4a25885c 100644
--- a/lib/class/stream.class.php
+++ b/lib/class/stream.class.php
@@ -142,17 +142,18 @@ class Stream {
* start_transcode
*
* This is a rather complex function that starts the transcoding or
- * resampling of a song and returns the opened file handle. A reference
- * to the song object is passed so that the changes we make in here
- * affect the external object, References++
+ * resampling of a song and returns the opened file handle.
*/
- public static function start_transcode(&$song, $song_name = 0) {
+ public static function start_transcode($song) {
+ $transcode_settings = $song->get_transcode_settings();
+ // Bail out early if we're unutterably broken
+ if ($transcode_settings == false) {
+ debug_event('stream', 'Transcode requested, but get_transcode_settings failed', 2);
+ return false;
+ }
- // Check to see if bitrates are set.
- // If so let's go ahead and optimize!
$max_bitrate = Config::get('max_bit_rate');
$min_bitrate = Config::get('min_bit_rate');
- $time = time();
// FIXME: This should be configurable for each output type
$user_sample_rate = Config::get('sample_rate');
@@ -161,10 +162,6 @@ class Stream {
$min_bitrate = $user_sample_rate;
}
- if (!$song_name) {
- $song_name = $song->f_artist_full . " - " . $song->title . "." . $song->type;
- }
-
// Are there site-wide constraints? (Dynamic downsampling.)
if ($max_bitrate > 1 ) {
$sql = 'SELECT COUNT(*) FROM `now_playing` ' .
@@ -180,15 +177,16 @@ class Stream {
$results = Dba::fetch_row($db_results);
$active_streams = intval($results[0]) ?: 0;
- debug_event('transcode', 'Active streams: ' . $active_streams, 5);
+ debug_event('stream', 'Active transcoding streams: ' . $active_streams, 5);
// We count as one for the algorithm
+ // FIXME: Should this reflect the actual bit rates?
$active_streams++;
$sample_rate = floor($max_bitrate / $active_streams);
// Exit if this would be insane
if ($sample_rate < ($min_bitrate ?: 8)) {
- debug_event('transcode', 'Max bandwidth already allocated. Active streams: ' . $active_streams, 2);
+ debug_event('stream', 'Max transcode bandwidth already allocated. Active streams: ' . $active_streams, 2);
header('HTTP/1.1 503 Service Temporarily Unavailable');
exit();
}
@@ -203,26 +201,23 @@ class Stream {
$sample_rate = $user_sample_rate;
}
- debug_event('transcode', 'Configured bitrate is ' . $sample_rate, 5);
+ debug_event('stream', 'Configured bitrate is ' . $sample_rate, 5);
- /* Validate the bitrate */
+ // Validate the bitrate
$sample_rate = self::validate_bitrate($sample_rate);
// Never upsample a song
- if ($song->resampled && ($sample_rate * 1000) > $song->bitrate) {
- debug_event('transcode', 'Clamping bitrate to avoid upsampling to ' . $sample_rate, 5);
+ if ($song->type == $transcode_settings['format'] && ($sample_rate * 1000) > $song->bitrate) {
+ debug_event('stream', 'Clamping bitrate to avoid upsampling to ' . $sample_rate, 5);
$sample_rate = self::validate_bitrate($song->bitrate / 1000);
}
- debug_event('transcode', 'Final bitrate is ' . $sample_rate, 5);
+ debug_event('stream', 'Final transcode bitrate is ' . $sample_rate, 5);
$song_file = scrub_arg($song->file);
- $transcode_command = $song->stream_cmd();
- if ($transcode_command == null) {
- debug_event('downsample', 'song->stream_cmd() returned null', 2);
- return null;
- }
+ // Finalise the command line
+ $command = $transcode_settings['command'];
$string_map = array(
'%FILE%' => $song_file,
@@ -230,20 +225,20 @@ class Stream {
);
foreach ($string_map as $search => $replace) {
- $transcode_command = str_replace($search, $replace, $transcode_command, $ret);
+ $command = str_replace($search, $replace, $command, $ret);
if (!$ret) {
debug_event('downsample', "$search not in downsample command", 5);
}
}
- debug_event('downsample', "Downsample command: $transcode_command", 3);
+ debug_event('downsample', "Downsample command: $command", 3);
- $fp = popen($transcode_command, 'rb');
-
- // Return our new handle
- return $fp;
+ return array(
+ 'handle' => popen($command, 'rb'),
+ 'format' => $transcode_settings['format']
+ );
- } // start_downsample
+ }
/**
* validate_bitrate
diff --git a/lib/class/video.class.php b/lib/class/video.class.php
index 22bafa19..3802048a 100644
--- a/lib/class/video.class.php
+++ b/lib/class/video.class.php
@@ -95,13 +95,9 @@ class Video extends database_object implements media {
} // format
- /**
- * native_stream
- * This returns true or false on the downsampling mojo
- */
- public function native_stream() {
+ public function get_stream_types() {
- return true;
+ return array('native');
} // native_stream
@@ -126,16 +122,13 @@ class Video extends database_object implements media {
} // play_url
/**
- * stream_cmd
- * test and see if the video needs to be natively streamed
- * if not it returns the transocding command from the config file
- * we can't use this->type because its been formated for the downsampling
+ * get_transcode_settings
+ *
+ * FIXME: Video transcoding is not implemented
*/
- public function stream_cmd() {
-
-
-
- } // stream_cmd
+ public function get_transcode_settings($target = null) {
+ return false;
+ }
/**
* has_flag