Getting Bitmap from Video decoded with Nestream AppendBytes (AS3)? - actionscript-3

I am wondering if someone who has handled NetStream.appendBytes in Flash knows how to get the bitmapData from a decoded video frame? I have already looked at this question but that is from 3 years ago and the more recent comment/answer seems to be gone. In 2014 has anyone managed to turn those bytes into a bitmap? I am working with Flash Player 11.8 and this is not a desktop/AIR app.
In the image below I can do steps 1) and 2) but there's a brick wall at step 3)
The problem is that simply using bitmapdata.draw(video_container); does not work but instead it throws a Policy File error even though I am using a byteArray (from local video file in the same directory as the SWF). No internet is even involved but Flash tells me that "No Policy File granted permission from the server" or such nonsense. I think the error is just a bail-out insteading of straight up saying "You are not allowed to do this.."
I have tried: trying to appease this Crossdomain.xml issue anyway and looking into all known security/domain settings. I came to the conclusion that the error is not the problem but a side effect of the issue.. The issue here being that: Flash Player is aware of the SWF's location and of any files local to it. That's okay when you pass a String as URL etc but when the Netstream data is not local to the SWF domain then it becomes a Policy File issue. Problem is my data is in the Memory not in a folder like the SWF and therefore cannot alllow bitmapData.draw since it cannot "police" an array of bytes, any known fixes for this?... (I can't even say the words I really wanted to use).
What I am trying to achieve: Is to essentially use Netstream as an H.263 or H.264 image decoder in the same way Loader is a JPEG-to-Bitmap decoder or LoadCompressed.. is an MP3-to-PCM decoder. You know, access the raw material (here RGB pixels), apply some effects functions and then send to screen or save to disk.

I know it is a little late, but I think I found a solution for your problem.
So, to avoid the Security sandbox violation #2123 Error, you have just to do like this :
// ...
net_stream.play(null);
net_stream.play('');
// ...
Hope that can help.

I know this question is a couple months old, but I wanted to post the correct answer (because I just had this problem as well and other will too).
Correct answer:
It's a bug that has been open at adobe for almost 2 years
Link to the bug on Adobe
Work Around until the bug gets fixed (I am using this and it works great):
Workaround using Sprite and graphics

To take a snapshot from a video stream we don't need NetStream.appendBytes which inject data into a NetStream object.
For that we can use BitmapData.draw which has some security constraints. That's why in many times we get a flash security error. About that, Adobe said :
"... This method is supported over RTMP in Flash Player 9.0.115.0 and later and in Adobe AIR. You can control access to streams on Flash Media Server in a server-side script. For more information, see the Client.audioSampleAccess and Client.videoSampleAccess properties in Server-Side ActionScript Language Reference for Adobe Flash Media Server. If the source object and (in the case of a Sprite or MovieClip object) all of its child objects do not come from the same domain as the caller, or are not in a content that is accessible to the caller by having called the Security.allowDomain() method, a call to the draw() throws a SecurityError exception. This restriction does not apply to AIR content in the application security sandbox. ...".
For crossdomain file creation and some other security config for AMS server, you can take a look on this post : Crossdomain Video Snapshot - Fixing BitmapData.draw() Security Sandbox Violation.
After allowing our script to get data from our video stream, we can pass to the code.
I wrote a code that play a video stream ( rtmp or http ) and take a snapshot to show it in the stage or save it as a file after applying a pixel effect :
const server:String = null; //'rtmp://localhost/vod'
const stream:String = 'stream'; // 'mp4:big_buck_bunny_480p_h264.mp4';
var nc:NetConnection;
var ns:NetStream;
var video:Video;
const jpg_quality:int = 80;
const px_size:int = 10;
nc = new NetConnection();
nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, function(e:AsyncErrorEvent):void{});
nc.addEventListener(NetStatusEvent.NET_STATUS, function(e:NetStatusEvent):void{
if(e.info.code == 'NetConnection.Connect.Success'){
ns = new NetStream(nc);
ns.addEventListener(NetStatusEvent.NET_STATUS, function(e:NetStatusEvent):void{});
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, function(e:AsyncErrorEvent):void{});
video = new Video(320, 180);
video.x = video.y = 10;
video.attachNetStream(ns);
addChild(video);
ns.play(stream);
}
})
nc.connect(server);
btn_show.addEventListener(
MouseEvent.CLICK,
function(e:MouseEvent): void{
var bmp:Bitmap = pixelate(video, px_size);
bmp.x = 10;
bmp.y = 220;
addChild(bmp);
}
)
btn_save.addEventListener(
MouseEvent.CLICK,
function(e:MouseEvent): void{
var bmp:Bitmap = pixelate(video, px_size);
var jpg_encoder:JPGEncoder = new JPGEncoder(80);
var jpg_stream:ByteArray = jpg_encoder.encode(bmp.bitmapData);
var file:FileReference = new FileReference();
file.save(jpg_stream, 'snapshot_'+int(ns.time)+'.jpg');
}
)
function pixelate(target:DisplayObject, px_size:uint):Bitmap {
var i:uint, j:uint = 0;
var s:uint = px_size;
var d:DisplayObject = target;
var w:uint = d.width;
var h:uint = d.height;
var bmd_src:BitmapData = new BitmapData(w, h);
bmd_src.draw(d);
var bmd_final:BitmapData = new BitmapData(w, h);
var rec:Rectangle = new Rectangle();
rec.width = rec.height = s;
for (i = 0; i < w; i += s){
for (j = 0; j < h; j += s){
rec.x = i;
rec.y = j;
bmd_final.fillRect(rec, bmd_src.getPixel32(i, j));
}
}
bmd_src.dispose();
bmd_src = null;
return new Bitmap(bmd_final);
}
Of course, this is just a simple example to show the manner to get a snapshot from a video stream, you should adapt and improve it to your needs ...
I hope all that can help you.

Related

add equalizer for online flash radio

i have tried add equalizer my online radio. i was used http://www.everyday3d.com/blog/index.php/2008/03/26/classic-sound-equalizer-in-flashas3/
flash source file . it's working fine when i am worked in flash ide. but on my server the equalizer doesnot show. but if the playing file is mp3 format it will worked but if we play the stream url it's not working. i dont know how can i fix this. i am using as3, i am new to flash. please help any one. thanks advance
the equalizer code
var es:EqualizerSettings = new EqualizerSettings();
es.numOfBars = 80;
es.height = 30;
es.barSize = 3;
es.vgrid = true;
es.hgrid = 2;
es.colorManager = new GradientBarColor(0xffff4444);
es.effect = EqualizerSettings.FX_REFLECTION;
var e:Equalizer = new Equalizer();
e.update(es);
e.x = 100;
e.y = 60;
addChild(e);
addEventListener(Event.ENTER_FRAME, e.render);
What Gio said, SoundMixer.computeSpectrum-based approach, such as the one linked in your question, suffers from security problems. But there are alternatives, for example check this code: http://wonderfl.net/c/euIb/read (some of stream URLs in it are dead, and it might not work right away - so try it with your own stream URL)

How to cache audio stream data and access it in AS3

I'm streaming an MP3 file in AS3. All is working fine (I can play it) but I'm looking to implement a 'seek' bar. This means I will need to cache the file (as it's being downloaded) and then access the cached data when the user seeks a specific time in the song.
The code to actually play the mp3 stream:
function openStream( stream )
{
var s:Sound = new Sound();
var req:URLRequest = new URLRequest(stream);
var context:SoundLoaderContext = new SoundLoaderContext(500, true);
s.load(req, context);
s.play();
}
So how would I cache the file as it's being downloaded and then access the data from the cache?
I know this is pretty far from a trivial task, so I would be grateful if you could even just provide a few links to some tutorials/docs/articles.
You do not need to cache the sound for this.
The downloaded sound data is is available as long as the sound object lives in memory.
So all you need to do is take the sound object outside the function into the class scope..
Also the play function returns the current SoundChannel used by the Sound.
private var snd:Sound = new Sound();
private var channel:SoundChannel;
function openStream( stream ) {
...
channel = snd.play();
}
To implement the seek functionality you may make use of,
bytesLoaded (To know how much of the sound is downloaded)
soundChannel.position (To know current sound position)

flash as3 and external text config file

My goal was to have an external text file config for a client. I didnt want to go through a crazy xml thing, I just wanted it to be simple to change.
I started with a urlLoader, and was able to dynamically generate an object no problem. This is the function which parses and sets the properties of the object.
function onLoaded(e:Event):void//initializes the config
{
var myString = String(e.target.data);
//trace(e.target.data);
//trace(myString);
var propsArray:Array = myString.split("\n");
for (var i = 0; i < propsArray.length; i++){
var thisLine:Array = propsArray[i].split("=");
var thisPropName:String = thisLine[0];
thisPropName = thisPropName.replace(rex,'');
var thisPropValue:String = thisLine[1];
thisPropValue = thisPropValue.replace(rex,'');
trace("thePropName is: " + thisPropName);
trace("thePropValue is: " + thisPropValue);
config[thisPropName] = thisPropValue;
}
}
The text file would just look something like:
gateway = "http://thePathto/theFile.php
toast = sonofabitch
timer = 5000
xSpeed = 5.0
That way, I could just put a little bit of as3 code in, type what things I wanted configured, then all I would have to do was type config.timer and
var myTimer:Timer = new Timer(Number(config.timer));
I think the problem is load order and scope. The config.timer is not created yet, so the timer is unable to access the value of the config.timer.
I'd look at using XML in future projects of this nature, however to answer your question:
I think the problem is load order and scope. The config.timer is not created yet, so the timer is unable to access the value of the config.timer.
Correct, you will need to initialize your Timer within the onLoaded() method, as the data will be received asynchronously and is not available until this happens.
ok not long ago i had created a download manager that uses this exact concept.
The link below will take you straight to the website where you can download the full swf including my source files. also this website is a good place for resources
http://ffiles.com/flash/web_applications_and_data/dynamic_download_manager_3529.html
Below is my loader:
addEventListener(Event.ENTER_FRAME, update);
var myLoader:URLLoader = new URLLoader();
myLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
myLoader.load(new URLRequest("settings.txt"));
myLoader.addEventListener(Event.COMPLETE, onDataLoad);
function onDataLoad(evt:Event)
{
box1.text = evt.target.data.Id_1;
box2.text = evt.target.data.Id_2;
box3.text = evt.target.data.Id_3;
box4.text = evt.target.data.Id_4;
box5.text = evt.target.data.Id_5;
}
Add some dynamic text boxes to stage and name them "box1, box2 ect..."
Now creat your text file:
Id_1=this is what ever you want
&Id_2=this is what ever you want
&Id_3=this is what ever you want
&Id_4=this is what ever you want
&Id_5=this is what ever you want
Hope this helps.

if I load a flv with netStream, how can I call a function when the flv stops playing

I have a website in ActionScript 3 that has lots of FLV animations that happen when you press buttons. Right now this is how I have it set up.
in AS3,
im loading FLv's (which are animations I exported in FLV form from After Effects)
with net stream. I have a timer set up for the same amount of length of time that the animations (FLV's) play and when the timer stops it calls a function that closes the stream, opens a new one and plays another video. The only problem I noticed using timers is that if the connection is slow and (animation)stops for a second, the timer keeps going, and calls the next flv too early.
Does anyone know a way to load a flv, or swf for that matter, at the end of play of the flv? so that the next FLV will always play at the end of the run time of the previous FLV, rather than using timers?
im thinking onComplete but I don't know how to implement that!?
Sequential playing is pretty easy to achieve with the OSMF framework, you should check it out. Google "osmf tutorials" and you should find a few tutorials online.
The framework is fairly recent, but it looks like it may become the de facto solution for media delivery in Flash as it's not limited to video but also audio & images.
As a developer you won't have to bother with the NetStream & NetConnection classes. Developing video solutions , as well as audio & images solutions should be streamlined and easier to handle. Only limitation is that it requires Flash 10
Here's some code for checking when a FLV ends with NetStream. I just provide snippets as I assume you got the FLV up and running already.
//create a netstream and pass in your connection
var netStream:NetStream = new NetStream(conn);
//add callback function for PlayStatus -event
var client : Object = {};
client.onPlayStatus = onPlayStatus;
netStream.client = client;
//attach your NetStream to the connection as usual
//---
//function that gets called onPlayStatus
function onPlayStatus(info : Object) : void {
trace("onPlayStatus:" +info.code + " " + info.duration);
if (info.code == "NetStream.Play.Complete") {
//play the next FLV and so on
}
}
EDIT: With your example code it will look something like this.
var nc:NetConnection = new NetConnection();
nc.connect(null);
var ns:NetStream = new NetStream(nc);
var listener:Object = new Object();
listener.onMetaData = function(md:Object):void{};
listener.onPlayStatus = function(info : Object) : void {
trace("onPlayStatus:" +info.code + " " + info.duration);
if (info.code == "NetStream.Play.Complete") {
//play the next FLV and so on
}
};
ns.client = listener;
vid1.attachNetStream(ns);
const moviename1:String = "moviename2.flv";
const moviename1:String = "moviename3.flv";
var movietoplay:String = "moviename.flv";
ns.play(movietoplay);

Actionscript 3: Monitoring the activity level for multiple Microphones doesn't seem to work

For a project I want to show all available webcams and microphones, so that the user can easily select whichever webcam/microphone combination they prefer. I run into an issue with the microphones listing though.
Each microphone is listed with an activity animation and it's name. I am able to list all Microphones just fine (using the Microphone.names Array), but it seems like I can only get the activity viewer to work for one microphone. The other microphones show up with '-1' activity, which (as far as I know) is Flex for 'present, but not in use'. When unplugging the microphone that does show activity, the next one (in my case, the mic-in line on my motherboard) shows up with '0' activity (it's not connected, so that makes sense).
During my testing I have a total of 3 microphones available, the not-connected onboard mic-in port, and two connected microphones.
For testing purposes I use a timer that traces the current microphone activity each 100ms and the graph is also shown.
It does not seem to matter what default microphone I set via flash' settings panel.
The code
I've only attached the revelant code snippets below to make it easier for you to read through them. Please let me know if you prefer the entire code.
Main application.mxml
Note: cont is a VBox. i is defined before this code snippet.
var mics:Array = Microphone.names;
for(i=0; i < mics.length; i++){
var mic:settingsMicEntry = new assets.settingsMicEntry;
mic.d = {name: mics[i], index: i};
cont.addChild(mic);
}
assets/settingsMicEntry.mxml
timer is defined before this code snippet. the SoundTransform is added to silence local microphone playback. Excluding this code does not solve the problem, sadly (I've tried). display is an MXML Canvas object.
mic = Microphone.getMicrophone(d.index);
if(mic){
// Temporary: The Microphones' visualizer
var bar:Box = new Box();
bar.y = 50;
bar.height = 0;
bar.width = 66;
bar.setStyle("backgroundColor", 0x003300);
display.addChild(bar);
var tf:SoundTransform = new SoundTransform(0);
mic.setLoopBack(true);
mic.soundTransform = tf;
timer = new Timer(100);
timer.addEventListener(TimerEvent.TIMER, function(e:TimerEvent):void{
var h:int = Math.floor((display.height/100)*mic.activityLevel);
bar.height = (h>-1) ? h : 0;
bar.y = (h>-1) ? display.height-h : display.height;
trace('TIMER: '+h+' from '+d.name);
});
timer.start();
}
I'm pulling my hear out here, so any help is much appreciated!
Thanks,
-Dave
Ps.: Pardon the messiness of the code!
You can set up a mock NetStream connection using the OSMF library.
You'll need to import the classes from the NetMocker project (under libs/adobe - org.osmf.netmocker) and the classes NetConnectionCodes and NetStreamCodes (under framework/OSMF - org.osmf.net).
Check out that you need to create one NetStream for each microphone