PDA

View Full Version : Challenge-ShoutCast Server Data. Stream something


bowljoman
06-04-2008, 02:16 AM
Hello, this is an action script file which connects to a shoutcast server and begins transmitting a NSV format bitstream.

The files below work. They stream the text "HELLO!!" through the video channel of a shoutcast server.

CHALLENGE! Send images, audio, objects, or anything cool that you want to stream to clients.

Requires a Shoutcast server running on 'localhost' or a server with socket policyfile.


To read and write NSV format easy, I rigged up this class from aol nsv C++ class. Package it into your workspace.

package com.thebitstream.nsv
{
import flash.utils.ByteArray;
import flash.utils.Endian;
public class BitStream
{
public var m_bits:ByteArray=new ByteArray();
public var m_curb:int=0;
public var m_used:int=0;
public var m_bitpos:int=0;
public var m_eof:int=0;
public function BitStream()
{
m_bits.endian=Endian.LITTLE_ENDIAN;
}
public function compact():void
{
//NOT BYTE ALIGNED!
var read:int=int(m_bitpos);
if(read<=0)return;
trace("COMPACTING!!!!! : "+read);
var resized:ByteArray=new ByteArray();
if(m_bits.length>m_bitpos/8)
resized.writeBytes(m_bits,read/8,m_bits.length-read/8);
m_used=resized.length*8;
m_bitpos=0;
m_bits=ByteArray(resized);
}
public function getbits(nbits:int):uint
{
var ret:uint=0;
var t:int=0;
if (nbits <= 0) return ret;
var sh:int=0;
t+=m_bitpos/8;
for (sh = 0; sh < nbits; sh ++)
{
ret|=((m_bits[t]>>(m_bitpos&7))&1) << sh;
if (!((++m_bitpos)&7)) t++;
}
return ret;
}
public function addInt(value:int):void
{
addByte((value)&0xFF);
addByte((value>>8)&0xFF);
addByte((value>>16)&0xFF);
addByte((value>>24)&0xFF);
}
public function readInt():uint
{
var ret:uint=(getbits(8))|
(getbits(8)<<8)|
(getbits(8)<<18)|
(getbits(8)<<24);
return ret;
}
public function readByte():uint
{
return getbits(8);
}
public function addByte(byte:uint):void
{
putbits(8,byte);
}
public function putbits(nbits:int, value:uint):void
{
while (nbits-- > 0)
{
m_curb|=(value&1)<<(m_used&7);
if (!((++m_used)&7))
{
m_bits.writeByte(m_curb);
m_curb=0;
}
value>>=1;
}
}
public function seek( nbits:int):void
{
m_bitpos+=nbits;
if (m_bitpos < 0)
m_bitpos=0;

m_eof=(m_bits.length*8 - m_bitpos>0)?0:1;
}

public function rewind():void
{
m_bitpos=0;
m_eof=0;
}
public function clear():void
{
m_bits=new ByteArray();
m_bits.endian=Endian.LITTLE_ENDIAN;
m_bitpos=0;
m_eof=0;
m_curb=0;
m_used=0
}
public function eof():int
{
return m_eof;
}
public function avail():int
{
if (m_eof)
return 0;
return m_bits.length*8 - m_bitpos;

}
public static function frate2double(fr:int):Number
{
var fratetab:Array=new Array( 30.0, 30.0*1000.0/1001.0,25.0,24.0*1000.0/1001.0);
if (!(fr&0x80)) return fr;
var sc:Number;
var d:int=fr&0x7f>>2;
if (d < 16) sc=1.0/(d+1);
else sc=d-15;
var r:int=fr&3;
return fratetab[r]*sc;
}
}
}




OK More code!

The challenge starts at the Adobe Socket sample.


package{import flash.errors.*;
import flash.events.*;
import flash.net.Socket;

public class CustomSocket extends Socket {
private var response:String;

public function CustomSocket(host:String = null, port:uint = 0) {
super(host, port);
configureListeners();
}

private function configureListeners():void {
addEventListener(Event.CLOSE, closeHandler);
addEventListener(Event.CONNECT, connectHandler);
addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
addEventListener(SecurityErrorEvent.SECURITY_ERROR , securityErrorHandler);
addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
}

public function writeln(str:String):void {
str += "\n";
try {
writeUTFBytes(str);
}
catch(e:IOError) {
trace(e);
}
}

private function sendRequest():void {
trace("sendRequest");
response = "";
writeln("changeme\nicy-name:Tests\nicy-genre:Live\nicy-pub:0\nicy-br:160\nicy-url:http://www.saladbowlguitar.com\nicy-reset:1\ncontent-type:video/nsv\n\n");
flush();
}

private function readResponse():void {
var str:String = readUTFBytes(bytesAvailable);
response += str;
}

private function closeHandler(event:Event):void {
trace("closeHandler: " + event);
trace(response.toString());
}

private function connectHandler(event:Event):void {
trace("connectHandler: " + event);
sendRequest();
}

private function ioErrorHandler(event:IOErrorEvent):void {
trace("ioErrorHandler: " + event);
}

private function securityErrorHandler(event:SecurityErrorEvent):voi d {
trace("securityErrorHandler: " + event);
}

private function socketDataHandler(event:ProgressEvent):void {
trace("socketDataHandler: " + event);
readResponse();

}
}
}


Ok now lets use that class to connect to a Shoutcast server and stream!

Create a new Action script project SocketExample.



package {
import com.thebitstream.nsv.BitStream;

import flash.display.Sprite;
import flash.events.Event;

public class SocketExample extends Sprite {
public var socket:CustomSocket = new CustomSocket();
public function SocketExample() {


socket.connect("localhost",8001);
//socket.connect("localhost",61);

this.addEventListener(Event.ENTER_FRAME,frame);

}
public function frame(e:Event):void
{
if(!socket.connected)return;


var bs:BitStream=new BitStream();
//write sync word
bs.putbits(8,String("N").charCodeAt());
bs.putbits(8,String("S").charCodeAt());
bs.putbits(8,String("V").charCodeAt());
bs.putbits(8,String("s").charCodeAt());
//Write data/video track 1 FourCC code or NONE
bs.putbits(8,String("T").charCodeAt());
bs.putbits(8,String("E").charCodeAt());
bs.putbits(8,String("X").charCodeAt());
bs.putbits(8,String("T").charCodeAt());
//Write data/audio track 2 FourCC code or NONE
bs.putbits(8,String("N").charCodeAt());
bs.putbits(8,String("O").charCodeAt());
bs.putbits(8,String("N").charCodeAt());
bs.putbits(8,String("E").charCodeAt());
// video Width+height
bs.putbits(16,320);
bs.putbits(16,240);
// Frame rate
bs.putbits(8,15);
// Track 1 and Track 2 Milliseconds offset
bs.putbits(16,0);
//Num Aux channels.
bs.putbits(4,0);
//video /data length
bs.putbits(20,7);
// audio /data length
bs.putbits(16,0);

//VD Could be a raw data buffer containing H264 or VP61.
bs.putbits(8,String("H").charCodeAt());
bs.putbits(8,String("E").charCodeAt());
bs.putbits(8,String("L").charCodeAt());
bs.putbits(8,String("L").charCodeAt());
bs.putbits(8,String("0").charCodeAt());
bs.putbits(8,String("!").charCodeAt());
bs.putbits(8,String("!").charCodeAt());

//No Audio Data Track; Could be mp3 or aac

//Send Frame
socket.writeBytes(bs.m_bits,0,bs.m_bits.length);
socket.flush();
}
}
}



Run that file and your shoutcast server should signify connection.

bowljoman
06-04-2008, 02:17 AM
Now. I have a flex file which I run in debug mode and I run SocketExample regularly.

Here is the flex app which connect to the shoutcast server and streams the content.



<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" frameRate="15" applicationComplete="init();" layout="absolute" width="240" height="120">
<mx:Script>
<![CDATA[
import com.thebitstream.nsv.BitStream;
public var us:URLStream=new URLStream();
public var bd:BitmapData;
public var bytes:Number=0;
public var lastBytes:Number=0;
public var frames:int=0;


public var bs:BitStream=new BitStream();


public function init():void
{
var ur:URLRequest=new URLRequest("http://localhost:8000/;file.nsv");
us.addEventListener(ProgressEvent.PROGRESS,loaded) ;
us.load(ur);
}
public function loaded(e:ProgressEvent):void
{

// Ignore empty interframes
if(e.bytesLoaded==lastBytes)
{
return;
}
var ba:ByteArray=new ByteArray();
ba.endian=Endian.LITTLE_ENDIAN;
lastBytes=e.bytesLoaded;

// Do we have full chunk?
if(e.bytesLoaded==e.bytesTotal)
{

//get the available bitstream
us.readBytes(ba,0,us.bytesAvailable);

//Check for SYNC
var s:String=String.fromCharCode(ba.readByte(),ba.read Byte(),ba.readByte(),ba.readByte());
if(s!="NSVs")
{
return;//Darn metadata!
}
// OK, data Frame!
var vid:String=String.fromCharCode(ba.readByte(),ba.re adByte(),ba.readByte(),ba.readByte());
var aud:String=String.fromCharCode(ba.readByte(),ba.re adByte(),ba.readByte(),ba.readByte());
var Swidth:uint=ba.readShort();
var Sheight:uint=ba.readShort();
var framerate:Number=this.frate2double(ba.readByte());
var offset:uint=ba.readShort();

// need to translate 4 bits to number aux channels, and 20 bits to Video data length.
var bs:BitStream=new BitStream();
bs.putbits(8,ba.readByte());
bs.putbits(8,ba.readByte());
bs.putbits(8,ba.readByte());
//read them out
bs.rewind();

var numAux:uint=bs.getbits(4);
var vl:uint=bs.getbits(20);

//OK, back to main bits payload.
// Audio Data length
var al:uint=ba.readShort();
//PAYLOADS!
var vd:ByteArray=new ByteArray();
if(vl>0)
{
ba.readBytes(vd,0,vl);
}
var ad:ByteArray=new ByteArray();
if(al>0)
{
ba.readBytes(ad,0,al);
}
trace("\nHeader :\t"+s);
frames++;
trace("Frame Number :\t"+frames);
trace("Video Type :\t"+vid);
trace("Audio Type :\t"+aud);
trace("Diminsions :\t"+ Swidth+" X "+Sheight);
trace("Framerate :\t"+framerate);
trace("Offset :\t"+offset);
trace("Num Aux\t"+numAux);
trace("Video Length\t"+vl);
trace("Audio Length\t"+al);
trace("Video Data : "+vd.toString());
trace("Audio Data : "+ad.toString());

}
}
public function frate2double(fr:int):Number
{
var fratetab:Array=new Array( 30.0, 30.0*1000.0/1001.0,25.0,24.0*1000.0/1001.0);
if (!(fr&0x80)) return fr;

var sc:Number;
var d:int=fr&0x7f>>2;
trace(d);
if (d < 16) sc=1.0/(d+1);
else sc=d-15;
trace(sc);
var r:int=fr&3;
trace(r);
trace(fratetab[r]);
return fratetab[r]*sc;
}


]]>
</mx:Script>
</mx:Application>

bowljoman
06-04-2008, 05:35 AM
This is the per-frame data packing limits.
Ooops. :o

#define NSV_MAX_AUDIO_LEN 0x8000 // 32kb
#define NSV_MAX_VIDEO_LEN 0x80000 // 512kb
#define NSV_MAX_AUX_LEN 0x8000 // 32kb for each aux stream
#define NSV_MAX_AUXSTREAMS 15 // 15 aux streams maximum

helpNeeded=true
06-04-2008, 08:13 AM
andy, people here are lazy to enter much simpler challenges.

bowljoman
06-04-2008, 03:30 PM
Ha !

k, oh well.

I was streaming my webcam using flash and shoutcast server last night!

mmmmkay. Moving on to the Next project...

bowljoman
06-09-2008, 04:05 AM
// ActionScript file
package {
import com.adobe.images.JPGEncoder;
import com.thebitstream.nsv.BitStream;

import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.media.Camera;
import flash.media.Video;
import flash.utils.ByteArray;

public class sender extends Sprite {
//CustomSender is the CustomSocket
public var socket:CustomSender = new CustomSender();
public var vid:Video=new Video(160,120);
public var cam:Camera=Camera.getCamera();
public var encoder:JPGEncoder=new JPGEncoder(50);

public function sender() {

vid.attachCamera(cam);

stage.frameRate=2;
//shoutcast!
socket.connect("66.135.37.225",8001);
addEventListener(Event.ENTER_FRAME,frame);

}
public function frame(e:Event):void
{
if(!socket.connected)return;





var bs:BitStream=new BitStream();
//write sync word
bs.putbits(8,String("N").charCodeAt());
bs.putbits(8,String("S").charCodeAt());
bs.putbits(8,String("V").charCodeAt());
bs.putbits(8,String("s").charCodeAt());
//Write data/video track 1 FourCC code or NONE
bs.putbits(8,String("J").charCodeAt());
bs.putbits(8,String("P").charCodeAt());
bs.putbits(8,String("E").charCodeAt());
bs.putbits(8,String("G").charCodeAt());
//Write data/audio track 2 FourCC code or NONE
bs.putbits(8,String("N").charCodeAt());
bs.putbits(8,String("O").charCodeAt());
bs.putbits(8,String("N").charCodeAt());
bs.putbits(8,String("E").charCodeAt());
// video Width+height
bs.putbits(16,320);
bs.putbits(16,240);
// Frame rate
bs.putbits(8,stage.frameRate);
// Track 1 and Track 2 Milliseconds offset
bs.putbits(16,0);
//Num Aux channels.
bs.putbits(4,0);
//VD Could be a raw data buffer containing H264 or VP61.
var bmd:BitmapData=new BitmapData(160,120,true,0x80FFFFFF)
bmd.draw(vid);

var pixels:ByteArray=encoder.encode(bmd);

//video /data length
bs.putbits(20,pixels.length);
// audio /data length
bs.putbits(16,0);
socket.writeBytes(bs.m_bits,0,bs.m_bits.length);

socket.writeBytes(pixels,0,pixels.length);




//No Audio Data Track; Could be mp3 or aac
trace(pixels.length);
//Send Frame

socket.flush();
}
}
}

bowljoman
06-09-2008, 04:10 AM
First change the sendRequest() in CustomSocket to




private function sendRequest():void {
trace("sendRequest");
response = "";
writeln("GET /;stream.nsv HTTP/1.0 User-Agent: FlashPlayer\n");
flush();
}


then use it here



package {
import com.thebitstream.nsv.BitStream;

import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.utils.ByteArray;


public class SocketExample extends Sprite {
public var socket:CustomSocket = new CustomSocket();
public var stream:BitStream=new BitStream();
public var syncron:Boolean=false;
public var frames:Number=0;
public function SocketExample() {

var l:Loader=new Loader();
addChildAt(l,0);
stage.frameRate=2;
socket.addEventListener(ProgressEvent.SOCKET_DATA, loaded);
socket.connect("66.135.37.225",8000);
this.addEventListener(Event.ENTER_FRAME,frame);

}
public function loaded(e:ProgressEvent):void
{

while(socket.bytesAvailable)
stream.addByte(socket.readByte());

if(syncron)return;
var sync:int=stream.m_bits.toString().search("NSVs");
if(sync>0)
{
trace("Frame+++++++++++++++++++++")
stream.rewind();
stream.seek(sync*8);
stream.compact();
var sin:String=new String(String.fromCharCode(stream.getbits(8))+ String.fromCharCode(stream.getbits(8))+String.from CharCode(stream.getbits(8))+String.fromCharCode(st ream.getbits(8)) );
if(sin!="NSVs")
{

stream.rewind();
return;
}
stream.rewind();
syncron=true;

}
else
{

}
trace(stream.m_bits.length);

}
public function frame(e:Event):void
{
if(!syncron)return;
var head:String=String.fromCharCode(stream.getbits(8)) ;
if(head!="N")
{
var sync:int=stream.m_bits.toString().search("SVs");
if(sync<=0)
{
stream.m_bitpos=stream.m_used;
stream.compact();
return;
}
{
stream.rewind();
stream.seek(sync*8);
}

}
else
{
head=String.fromCharCode(stream.getbits(8),stream. getbits(8),stream.getbits(8));
if(head!="SVs")
{
stream.compact();
trace("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@");
syncron=false;
return;
}
}
var vid:String=String.fromCharCode(stream.readByte(),s tream.readByte(),stream.readByte(),stream.readByte ());
var aud:String=String.fromCharCode(stream.readByte(),s tream.readByte(),stream.readByte(),stream.readByte ());
var Swidth:uint=stream.getbits(16);
var Sheight:uint=stream.getbits(16);
var framerate:Number=this.frate2double(stream.getbits( 8));
var offset:uint=stream.getbits(16);


var numAux:uint=stream.getbits(4);
var vl:uint=stream.getbits(20);
if(!(stream.avail()/16)>vl)
{
stream.rewind();

return;
}

//OK, back to main bits payload.
// Audio Data length
var i:int=0;
var al:uint=stream.getbits(16);
//PAYLOADS!
var vd:ByteArray=new ByteArray();
if(vl>0)
{
for(i=0;i<vl;i++)
{
vd.writeByte(stream.readByte());
}
//ba.readBytes(vd,0,vl);
}
var ad:ByteArray=new ByteArray();
if(al>0)
{
for(i=0;i<al;i++)
{
ad.writeByte(stream.readByte());
}
}

frames++;
if(vid=="JPEG")
{
var loader:Loader=new Loader();

loader.contentLoaderInfo.addEventListener(Event.CO MPLETE,loaded2);
loader.loadBytes(vd);



}
trace("Frame Number :\t"+frames);
trace("Video Type :\t"+vid);
trace("Audio Type :\t"+aud);
trace("Diminsions :\t"+ Swidth+" X "+Sheight);
trace("Framerate :\t"+framerate);
trace("Offset :\t"+offset);
trace("Num Aux\t"+numAux);
trace("Video Length\t"+vl);
trace("Audio Length\t"+al);
trace("Video Data : "+vd.length);
trace("Audio Data : "+ad.length);
stream.compact();

}
public function loaded2(e:Event):void
{
var l:Loader=e.target.loader;
l.scaleX=2;l.scaleY=2;
var dsp:DisplayObject=this.removeChildAt(0);
addChild(l);
dsp=null;

}
public function frate2double(fr:int):Number
{
var fratetab:Array=new Array( 30.0, 30.0*1000.0/1001.0,25.0,24.0*1000.0/1001.0);
if (!(fr&0x80)) return fr;

var sc:Number;
var d:int=fr&0x7f>>2;
trace(d);
if (d < 16) sc=1.0/(d+1);
else sc=d-15;
trace(sc);
var r:int=fr&3;
trace(r);
trace(fratetab[r]);
return fratetab[r]*sc;
}
}
}