Archive

Archive for September, 2009

Java: Multiple Thread Controller

September 10th, 2009 No comments

ThreadThis example is for those of you writing server side Java daemons who want to take full control over how much CPU is used on multi-core machines. Essentially you have a controller objected which when constructed creates up to maxThreads worth of “thread workers” (this is your thread pool) which can be assigned to generic code of your choice, in the form of an IRunnableThread, which is basically a Java Runnable object.

ThreadTester is a basic implementation of an IRunnableThread which contains a simple unit test to show the thread controller working. Of course you can swap out ThreadTester for you own implementation.

The Daemon main statement shows how to start and use the thread controller at the upper most level. The argument to thread controller is the number of threads you require for simultaneous processing, in this example its 3

package ThreadControl;

import java.util.LinkedList;
import ThreadControl.ThreadWorker;

public class ThreadController implements Runnable{

private int maxThreads;

private ThreadWorker[] threads;

public static LinkedList<IRunnableThread> queue;

    /**
     *
     */

    public ThreadController(int maxThreads){
        this.maxThreads = maxThreads;
        queue = new LinkedList<IRunnableThread>();
        threads = new ThreadWorker[maxThreads];
    }

    public static int queueSize(){
    	return queue.size();
    }

    public int maxQueueSize(){
    	return maxThreads;
    }

    public synchronized void push(IRunnableThread threadCode){
    	 queue.addLast(threadCode);
         queue.notify();
    }

    public void push(IRunnableThread threadCode){
    	synchronized(queue) {
          queue.addLast(threadCode);
          queue.notify();
        }
    }

    public void run() {
        for (int i=0; i<maxThreads; i++) {
            threads[i] = new ThreadWorker();
            threads[i].start();
        }
    }

}

The implementation for one of the thread workers that is part of your thread pool of size: maxThreads

package ThreadControl;

import ThreadControl.ThreadController;

public class ThreadWorker extends Thread{

	public void run(){
		IRunnableThread r;
		
		while (true){
			synchronized(ThreadController.queue){
				while(ThreadController.queue.isEmpty()){
					try{
						ThreadController.queue.wait();
					}
					catch (InterruptedException ignored){
						
					}
				}
				r = ThreadController.queue.removeFirst();
			}
			// If we don't catch RuntimeException, 
			// the pool could leak threads
			try{
				r.setThreadId(Long.toString(this.getId()));
                r.run();
            }
			catch (RuntimeException e) {
                 // You might want to log something here
			}
		}
	}
	
}

Runnable thread interface

package ThreadControl;

public interface IRunnableThread extends Runnable{
	
	public String getThreadId();

	public void setThreadId(String threadId);
	
}

Test implementation for IRunnableThread,

package ThreadControl;

public class ThreadTester implements IRunnableThread{
	
	private final static int noAlertMessages = 5; 
	
	// In milliseconds
	private int messageDelay = 1000;
	
	private String testId = "";

	private String threadId = "";
	
	public ThreadTester(String testId){
		this.testId = testId;
	}
	
	public ThreadTester(String testId,int messageDelay){
		this.testId = testId;
		this.messageDelay = messageDelay;
	}
	
	public void run(){
		for(int i=0;i<noAlertMessages;i++){
			System.out.print("Thread Id: " + threadId + " - [" + testId + "]: test message #" + (i + 1) + "\n");
			System.out.print("Thread Queue Size: " + ThreadController.queueSize() + "\n");
			try{
				Thread.sleep(messageDelay);
			}
			catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.print("*** " + testId + " complete! ***\n");
	}

	public String getThreadId() {
		return threadId;
	}

	public void setThreadId(String threadId) {
		this.threadId = threadId;
	}

}

Main statement where the test case is demonstrated

import ThreadControl.ThreadController;
import ThreadControl.ThreadTester;

public class Daemon {

	public static void main(String[] args) {
		ThreadController threadController = new ThreadController(3);
		
		try{
			new Thread(threadController).start();
		} 
		catch (Exception e) {
			e.printStackTrace();
		}
		
		threadController.push(new ThreadTester("Test 1",5000));
		threadController.push(new ThreadTester("Test 2",333));
		threadController.push(new ThreadTester("Test 3",777));
		threadController.push(new ThreadTester("Test 4",450));
		threadController.push(new ThreadTester("Test 5",1024));
	}

}
Categories: Code, General, Java Tags: , ,

ASF Streaming Playback via VLC

September 4th, 2009 2 comments

I have a old platform dependent Linksys WVC54G (P.O.S) which only streams in ASF format and I needed/expected to have the flexibility to view this video format on different platforms (in my case OSX or Linux) . VLC was the obvious choice but as it turned out it wasn’t that simple.

You can see on line 90 of the VLC debug below: main debug: EOF reached

As it turns out it’s not a complete file (by nature as it’s streaming) so EOF is prematurely reached causing the video to fail :(

main debug: processing request item http://x.x.x.x/img/video.asf node Playlist skip 0
main debug: resyncing on http://x.x.x.x/img/video.asf
main debug: http://x.x.x.x/img/video.asf is at 0
main debug: starting new item
main debug: creating new input thread
main debug: Creating an input for 'http://x.x.x.x/img/video.asf'
main debug: thread (input) created at priority 1 (../.././src/input/input.c:230)
qt4 debug: IM: Setting an input
main debug: thread started
main debug: using timeshift granularity of 50 MBytes
main debug: using timeshift path 'C:\x\x\LOCALS~1\Temp'
main debug: `http://x.x.x.x/img/video.asf' gives access `http' demux `' path `x.x.x.x/img/video.asf'
main debug: creating demux: access='http' demux='' path='x.x.x.x/img/video.asf'
main debug: looking for access_demux module: 0 candidates
main debug: no access_demux module matched "http"
main debug: TIMER module_need() : 0.000 ms - Total 0.000 ms / 1 intvls (Avg 0.000 ms)
main debug: creating access 'http' path='x.x.x.x/img/video.asf'
main debug: looking for access module: 2 candidates
access_http debug: http: server='x.x.x.x' port=80 file='/img/video.asf
main debug: net: connecting to x.x.x.x port 80
main debug: connection: Resource temporarily unavailable
qt4 debug: Updating the geometry
qt4 debug: Updating the geometry
main debug: connection succeeded (socket = 696)
access_http debug: protocol 'HTTP' answer code 206
access_http debug: Server: thttpd/2.20b 10oct00
access_http debug: Content-Type: application/octet-stream
access_http debug: Connection: close
access_http debug: stream size=-1,pos=0,remaining=4518
access_http debug: this frame size=4518
main debug: using access module "access_http"
main debug: TIMER module_need() : 656.000 ms - Total 656.000 ms / 1 intvls (Avg 656.000 ms)
main debug: Using AStream*Stream
main debug: pre buffering
main debug: received first data after 0 ms
main debug: pre-buffering done 481 bytes in 0s - 469726 kbytes/s
main debug: looking for stream_filter module: 2 candidates
main debug: TIMER module_need() : 0.000 ms - Total 0.000 ms / 1 intvls (Avg 0.000 ms)
main debug: looking for stream_filter module: 1 candidate
main debug: using stream_filter module "stream_filter_record"
main debug: TIMER module_need() : 0.000 ms - Total 0.000 ms / 1 intvls (Avg 0.000 ms)
main debug: creating demux: access='http' demux='' path='x.x.x.x/img/video.asf'
main debug: looking for demux module: 50 candidates
asf debug: found object guid: 0x75b22630-0x668e-0x11cf-0xa6d900aa0062ce6c size:431
asf debug: read "header object" subobj:4, reserved1:1, reserved2:2
asf debug: found object guid: 0x8cabdca1-0xa947-0x11cf-0x8ee400c00c205365 size:104
asf debug: read "file properties object" file_id:0x67452301-0xab89-0xefcd-0x0000000000000000 file_size:4294967295 creation_date:0 data_packets_count:4294967295 play_duration:4294967295 send_duration:16777215 preroll:0 flags:1 min_data_packet_size:2000  max_data_packet_size:2000 max_bitrate:916000
asf debug: found object guid: 0xb7dc0791-0xa9b7-0x11cf-0x8ee600c00c205365 size:147
asf debug: read "stream Properties object" stream_type:0xbc19efc0-0x5b4d-0x11cf-0xa8fd00805f5c442b error_correction_type:0x20fb5700-0x5b55-0x11cf-0xa8fd00805f5c442b time_offset:0 type_specific_data_length:69 error_correction_data_length:0 flags:0x1 stream_number:1
asf debug: found object guid: 0xb7dc0791-0xa9b7-0x11cf-0x8ee600c00c205365 size:104
asf debug: read "stream Properties object" stream_type:0xf8699e40-0x5b4d-0x11cf-0xa8fd00805f5c442b error_correction_type:0xbfc3cd50-0x618f-0x11cf-0x8bb200aa00b4e220 time_offset:0 type_specific_data_length:18 error_correction_data_length:8 flags:0x2 stream_number:2
asf debug: found object guid: 0x5fbf03b5-0xa92e-0x11cf-0x8ee300c00c205365 size:46
asf debug: read "header extension object" reserved1:0xabd3d211-0xa9ba-0x11cf-0x8ee600c00c205365 reserved2:6 header_extension_size:0
asf debug: found object guid: 0x75b22636-0x668e-0x11cf-0xa6d900aa0062ce6c size:-72057594037927937
asf debug: read "data object" file_id:0x67452301-0xab89-0xefcd-0x0000000000000000 total data packet:0 reserved:257
asf debug: + 'Unknown' GUID 0x0-0x0-0x0-0x0000000000000000 size:0pos:0
asf debug:      + 'Header' GUID 0x75b22630-0x668e-0x11cf-0xa6d900aa0062ce6c size:431pos:0
asf debug:      |    + 'File Properties' GUID 0x8cabdca1-0xa947-0x11cf-0x8ee400c00c205365 size:104pos:30
asf debug:      |    + 'Stream Properties' GUID 0xb7dc0791-0xa9b7-0x11cf-0x8ee600c00c205365 size:147pos:134
asf debug:      |    + 'Stream Properties' GUID 0xb7dc0791-0xa9b7-0x11cf-0x8ee600c00c205365 size:104pos:281
asf debug:      |    + 'Header Extension' GUID 0x5fbf03b5-0xa92e-0x11cf-0x8ee300c00c205365 size:46pos:385
asf debug:      + 'Data' GUID 0x75b22636-0x668e-0x11cf-0xa6d900aa0062ce6c size:18374686479671623679pos:431
asf debug: found 2 streams
access_http warning: unimplemented query in control
main debug: selecting program id=0
asf debug: added new video stream(ID:1)
access_http warning: unimplemented query in control
asf debug: added new audio stream(codec:0x45,ID:2)
main debug: using demux module "asf"
main debug: TIMER module_need() : 8.000 ms - Total 8.000 ms / 1 intvls (Avg 8.000 ms)
main debug: looking for a subtitle file in C:\Program Files\VideoLAN\VLC\
main debug: looking for decoder module: 35 candidates
avcodec debug: libavcodec already initialized
avcodec debug: using direct rendering
avcodec debug: ffmpeg codec (MPEG-4 Video) started
main debug: using decoder module "avcodec"
main debug: TIMER module_need() : 4.000 ms - Total 4.000 ms / 1 intvls (Avg 4.000 ms)
main debug: thread (decoder) created at priority 0 (../.././src/input/decoder.c:315)
main debug: thread started
main debug: looking for decoder module: 35 candidates
avcodec debug: libavcodec already initialized
avcodec debug: ffmpeg codec (G.726 ADPCM Audio) started
avcodec debug: Using 192000 bytes output buffer
main debug: using decoder module "avcodec"
main debug: TIMER module_need() : 4.000 ms - Total 4.000 ms / 1 intvls (Avg 4.000 ms)
main debug: thread (decoder) created at priority 2 (../.././src/input/decoder.c:315)
main debug: thread started
main debug: `http://x.x.x.x/img/video.asf' successfully opened
asf warning: cannot peek while getting new packet, EOF ?
main debug: EOF reached
main debug: finished input
main debug: waitpipe: object killed
main debug: thread times: real 0m0.000000s, kernel 0m0.000000s, user 0m0.000000s
avcodec debug: ffmpeg codec (MPEG-4 Video) stopped
main debug: removing module "avcodec"
main debug: killing decoder fourcc `MP4S', 0 PES in FIFO
main debug: thread times: real 0m0.000000s, kernel 0m0.000000s, user 0m0.000000s
avcodec debug: ffmpeg codec (G.726 ADPCM Audio) stopped
main debug: removing module "avcodec"
main debug: killing decoder fourcc `g726', 0 PES in FIFO
asf debug: free asf object 0x8cabdca1-0xa947-0x11cf-0x8ee400c00c205365
asf debug: free asf object 0xb7dc0791-0xa9b7-0x11cf-0x8ee600c00c205365
asf debug: free asf object 0xb7dc0791-0xa9b7-0x11cf-0x8ee600c00c205365
asf debug: free asf object 0x5fbf03b5-0xa92e-0x11cf-0x8ee300c00c205365
asf debug: free asf object 0x75b22630-0x668e-0x11cf-0xa6d900aa0062ce6c
asf debug: free asf object 0x75b22636-0x668e-0x11cf-0xa6d900aa0062ce6c
main debug: Program doesn't contain anymore ES
main debug: removing module "asf"
main debug: removing module "stream_filter_record"
main debug: removing module "access_http"
main debug: thread ended
main debug: dead input
main debug: thread times: real 0m0.671875s, kernel 0m0.000000s, user 0m0.000000s
main debug: changing item without a request (current 0/1)
main debug: nothing to play
qt4 debug: IM: Deleting the input
qt4 debug: Updating the geometry
qt4 debug: Updating the geometry
main debug: TIMER input launching for 'http://x.x.x.x/img/video.asf' : 680.000 ms - Total 680.000 ms / 1 intvls (Avg 680.000 ms)

After a little digging around I found a very handy option under

  • Preferences
  • Input/Codecs
  • Access Modules
  • HTTP(S)
  • Continuous Stream (tickbox)

After ticking Continuous Stream restart the video and you should be in business.

Categories: General Tags: , ,