last_preview_mode = preview_mode;
b_map.put( "msg", MessageText.getString( last_preview_mode?"stream.analysing.media.preview":"stream.analysing.media" ));
}
DownloadStats stats = download.getStats();
b_map.put( "dl_rate", stats.getDownloadAverage());
b_map.put( "dl_size", stats.getDownloaded());
b_map.put( "dl_time", SystemTime.getMonotonousTime() - stream_start );
try{
buffering_method.invoke(player, new Object[] { b_map });
}catch( Throwable e ){
}
}
}
}
}.start();
sem.reserve();
synchronized( StreamManager.this ){
if ( cancelled ){
throw( new Exception( "Cancelled" ));
}
active_job = null;
active_sem = null;
}
if ( error[0] != null ){
throw( error[0] );
}
duration = properties[0];
video_width = properties[1];
video_height = properties[2];
if ( duration > 0 ){
if ( map == null ){
map = new HashMap<String, Map<String,Object>>();
}else{
map = new HashMap<String, Map<String,Object>>( map );
}
Map<String,Object> file_map = map.get( String.valueOf( file_index ));
if ( file_map == null ){
file_map = new HashMap<String, Object>();
map.put( String.valueOf( file_index ), file_map );
}
file_map.put( "duration", duration );
file_map.put( "video_width", video_width );
file_map.put( "video_height", video_height );
download.setMapAttribute( mi_ta, map );
}
}catch( Throwable e ){
tj.removeForce();
throw( e );
}
}catch( Throwable e ){
throw( new Exception( "Media analysis failed", e ));
}finally{
}
}else{
duration = l_duration;
video_width = l_video_width==null?0:l_video_width;
video_height = l_video_height==null?0:l_video_height;
}
if ( video_width == 0 || video_height == 0){
throw( new Exception( "Media analysis failed - video stream not found" ));
}
if ( duration == 0 ){
throw( new Exception( "Media analysis failed - duration unknown" ));
}
listener.updateActivity( "MetaData read: duration=" + TimeFormatter.formatColon( duration/1000) + ", width=" + video_width + ", height=" + video_height );
Method smd_method = player.getClass().getMethod( "setMetaData", new Class[] { Map.class });
Map<String,Object> md_map = new HashMap<String,Object>();
md_map.put( "duration", duration );
md_map.put( "width", video_width );
md_map.put( "height", video_height );
smd_method.invoke( player, new Object[] { md_map });
final long bytes_per_sec = file.getLength() / (duration/1000);
long dl_lim_max = COConfigurationManager.getIntParameter( "Plugin.azemp.azemp.config.dl_lim_max" ) * 1024L;
long dl_lim_extra = COConfigurationManager.getIntParameter( "Plugin.azemp.azemp.config.dl_lim_extra" ) * 1024L;
existing_dl_limit = download.getDownloadRateLimitBytesPerSecond();
long required_limit = Math.max( dl_lim_max, bytes_per_sec + dl_lim_extra );
if ( required_limit > 0 ){
download.setDownloadRateLimitBytesPerSecond((int)required_limit );
}
listener.updateActivity( "Average rate=" + DisplayFormatters.formatByteCountToKiBEtcPerSec( bytes_per_sec ) + ", applied dl limit=" + DisplayFormatters.formatByteCountToKiBEtcPerSec( required_limit ));
synchronized( StreamManager.this ){
if ( cancelled ){
throw( new Exception( "Cancelled" ));
}
active_edm.setExplicitProgressive( BUFFER_SECS, bytes_per_sec, file_index );
if ( !active_edm.setProgressiveMode( true )){
throw( new Exception( "Failed to set download as progressive" ));
}
active_edm_activated = true;
}
new AEThread2( "streamMon" )
{
public void
run()
{
final int TIMER_PERIOD = 250;
final int PLAY_STATS_PERIOD = 5000;
final int PLAY_STATS_TICKS = PLAY_STATS_PERIOD / TIMER_PERIOD;
final int DL_STARTUP_PERIOD = 5000;
final int DL_STARTUP_TICKS = DL_STARTUP_PERIOD / TIMER_PERIOD;
boolean playback_started = false;
boolean playback_paused = false;
boolean error_reported = false;
try{
Method start_method = player.getClass().getMethod( "startPlayback", new Class[] { URL.class });
Method pause_method = player.getClass().getMethod( "pausePlayback", new Class[] {});
Method resume_method = player.getClass().getMethod( "resumePlayback", new Class[] {});
Method buffering_method = player.getClass().getMethod( "bufferingPlayback", new Class[] { Map.class });
Method play_stats_method = player.getClass().getMethod( "playStats", new Class[] { Map.class });
int tick_count = 0;
while( !cancelled ){
tick_count++;
int dm_state = dm.getState();
boolean complete = file.getLength() == file.getDownloaded();
if ( !complete ){
if ( dm_state == DownloadManager.STATE_ERROR ||
dm_state == DownloadManager.STATE_STOPPED ||
dm_state == DownloadManager.STATE_QUEUED ){
if ( tick_count >= DL_STARTUP_TICKS ){
throw( new Exception( "Streaming abandoned, download isn't running" ));
}
}
if ( !active_edm.getProgressiveMode()){
complete = file.getLength() == file.getDownloaded();
if ( !complete ){
throw( new Exception( "Streaming mode abandoned for download" ));
}
}
}
long[] details = updateETA( active_edm );
int eta = (int)details[0];
int buffer_secs = (int)details[1];
long buffer = details[2];
listener.updateStats( eta, buffer_secs, buffer, BUFFER_SECS );
boolean playable;
int buffer_to_use = playback_started?BUFFER_MIN_SECS:BUFFER_SECS;
if ( complete ){
playable = true;
}else{
playable = buffer_secs > buffer_to_use;
playable = playable && ( eta <= 0 || (playback_started && !playback_paused ) || preview_mode );
}
if ( playback_started ){
if ( playable ){
if ( playback_paused ){
listener.updateActivity( "Resuming playback" );
resume_method.invoke(player, new Object[] {});
playback_paused = false;
}
}else{
if ( !playback_paused ){
listener.updateActivity( "Pausing playback to prevent stall" );
pause_method.invoke(player, new Object[] {});
playback_paused = true;
}
}
}else{
if ( playable ){
listener.ready();
start_method.invoke(player, new Object[] { url });
playback_started = true;
}
}
if ( playable ){
if ( tick_count % PLAY_STATS_TICKS == 0 ){
long contiguous_done = active_edm.getContiguousAvailableBytes( active_edm.getPrimaryFile().getIndex(), 0, 0 );
Map<String,Object> map = new HashMap<String,Object>();
map.put( "buffer_min", new Long( BUFFER_SECS ));
map.put( "buffer_secs", new Integer( buffer_secs ));
map.put( "buffer_bytes", new Long( buffer ));
map.put( "stream_rate", bytes_per_sec );
DownloadStats stats = download.getStats();
map.put( "dl_rate", stats.getDownloadAverage());
map.put( "dl_size", stats.getDownloaded());
map.put( "dl_time", SystemTime.getMonotonousTime() - stream_start );
map.put( "duration", duration );
map.put( "file_size", file.getLength());
map.put( "cont_done", contiguous_done );
play_stats_method.invoke(player, new Object[] { map });
}
}else{
DownloadStats stats = download.getStats();
Map<String,Object> map = new HashMap<String,Object>();
map.put( "state", new Integer( 2 ));
if ( preview_mode && !complete ){
long rate = stats.getDownloadAverage();
int preview_eta;
if ( rate <= 0 ){
preview_eta = Integer.MAX_VALUE;
}else{
double secs_per_sec = ((double)bytes_per_sec)/rate;
preview_eta = (int)(( buffer_to_use - buffer_secs ) * secs_per_sec);
}
map.put( "eta", new Integer( preview_eta ));
map.put( "preview", 1 );
}else{
map.put( "eta", new Integer( eta ));
map.put( "preview", 0 );
}
map.put( "buffer_min", new Long( BUFFER_SECS ));
map.put( "buffer_secs", new Integer( buffer_secs ));
map.put( "buffer_bytes", new Long( buffer ));
map.put( "stream_rate", bytes_per_sec );
map.put( "dl_rate", stats.getDownloadAverage());
map.put( "dl_size", stats.getDownloaded());
map.put( "dl_time", SystemTime.getMonotonousTime() - stream_start );
buffering_method.invoke(player, new Object[] { map });
}