0

I'm trying to make a web app that lets the user record a video message. I'm trying to get the best quality possible (even if it means long upload times). I manage to get recording working with ns.publish("livestream", "live"); The server code looks like this:

Client.prototype.startRecord = function( source, destination ) {
        trace("recording Stream: " + source + " to: " + destination);
        this.newStream = Stream.get(destination);
        this.fileRecording = destination;
        trace(this.fileRecording);

        if (this.newStream)
        {
            this.newStream.onStatus = function (info) {
                //trace(info.code );
                if (info.code == "NetStream.Play.PublishNotify") {              
                    trace("start recording");
                    this.record();
                }   
            }

            this.newStream.play(source)

        }
    }

    Client.prototype.stopRecord = function() {
        trace("stopping Recording");
        this.newStream.record(false);
        this.newStream.play(false);
    }

    Client.prototype.getFiles = function() {
        var fileRecord = new File("/streams/_definst_/"+this.fileRecording+".flv");

        if (fileRecord.exists)
        {
            return this.fileRecording;
        }

        return "error recording";
    }


    application.onConnect = function(clObj) {
        this.acceptConnection(clObj);
    }

The problem is that the quality is not great. I tried using ns.publish("livestream", "record"); , but its making 2 files on the server and quality doesn't improve, any suggestion? I can also upload the client code if you need it.

Client code:

import flash.media.*;
import flash.events.*;
import flash.net.*;
import flash.utils.getTimer;

var vid:Video;
var mic:Microphone;
var cam:Camera;
var fileListObj:Object = {};
var ns:NetStream;
var nc:NetConnection;
var recordingName:String;

initCamera();

function initCamera ():void
{
    if (Camera.isSupported)
    {
        cam = Camera.getCamera();

        cam.setMode (800, 480, 24);
        //cam.setQuality(0, 90);
        vid = new Video(cam.width,cam.height);

        vid.attachCamera (cam);

        if (Microphone.isSupported)
        {
            mic = Microphone.getEnhancedMicrophone();       
        }

        this.addChildAt (vid, 1);

        vid.x = (800 - vid.width) >> 1;
        vid.y = (480 - vid.height) >> 1;        

        initConnection();
    }
    else
    {
        trace ("no camera");
    }
}


function initConnection ():void
{
    nc = new NetConnection();

    nc.addEventListener (NetStatusEvent.NET_STATUS, netStatusHandler);
    nc.addEventListener (AsyncErrorEvent.ASYNC_ERROR, function (event:AsyncErrorEvent):void {trace("error");});

    nc.connect ("rtmp://adrian7.srfms.com/nabCapture");
}



function recordVideo (event:MouseEvent):void
{
    if (record_mc.label == "Record")
    {
        record_mc.label = "Stop Record";

        var currentTime:Date = new Date();

        recordingName = "myRecording"+getTimer()+""+currentTime.time;

        nc.call ("startRecord", new Responder(startPublish), "livestream", recordingName);


    }
    else
    {
        record_mc.enabled = false;
        record_mc.label = "Record";

        nc.call ("stopRecord", null);
        ns.close();

        nc.call ("getFiles", new Responder(onResultFileListObj, null));     
    }
}

function startPublish (result:Object):void
{
    ns.publish("livestream", "live");
}

function netStatusHandler (event:NetStatusEvent):void
{
    //trace (event.info.code);
    if (event.info.code == "NetConnection.Connect.Success")
    {
        ns = new NetStream(nc);

        ns.attachCamera (cam);
        if (mic)
        {
            ns.attachAudio(mic);
        }

        record_mc.enabled = true;
        record_mc.addEventListener (MouseEvent.CLICK, recordVideo);
    }
}



function onResultFileListObj (resultObj:Object):void 
{
    if (String(resultObj) != "error recording")
    {
        recordingName = String(resultObj);

        see_mc.enabled = true;
        see_mc.addEventListener(MouseEvent.CLICK, function (event:MouseEvent):void {
                        navigateToURL(new URLRequest("http://www.labs.adrian281990.com/fms_demo1/index.php?id=" + recordingName), "_self");
                                });
    }
}
  • Yes, show the client code. The client can configure the webcam's capture resolution with [Camera.setMode()](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/Camera.html#setMode()) and set some a preference for picture quality or bandwidth consumption with [Camera.setQuality()](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/Camera.html#setQuality()) – Sunil D. Jul 04 '12 at 10:53
  • cam = Camera.getCamera(); cam.setMode (800, 480, 24); //cam.setQuality(0, 90); vid = new Video(cam.width,cam.height); vid.attachCamera (cam); if (Microphone.isSupported) { mic = Microphone.getEnhancedMicrophone(); } – user1500639 Jul 04 '12 at 18:02
  • Videos (and the resolutions that web cameras support) are usually in a 4:3 ratio. The web cam probably does not support 800x480, so Flash tries to find something close. The result may not be so good. Try using different values: 800x600, 640x480, 480x360 or some other values w/a 4:3 ratio. If the end result needs to be some other size you can scale or crop the video (w/some effort). I get great results at 480x360. – Sunil D. Jul 07 '12 at 01:52

1 Answers1

0

Use a common resolution and avoid the default setQuality values

You should start by making the following to changes:

  1. Use a common resolution like 640x480 and a frame rate of 30
  2. Avoid the default cam.setQuality settings and use cam.setQuality(0,90)

the above translates in the following client AS3 code:

cam.setMode (640, 480, 24);
cam.setQuality(0, 90);

cam.setMode(640,480,24);

What happens is that you're currently requesting 800x480@24fps from the webcam. 800x480@24fps is not a widely supported resolution which means on most webcams you'll get whatever the webcam responds with (which might not be the best quality). Requesting a common resolution like 640 x 480 @ 30fps will ensure you're getting just that on most webcams.

cam.setQuality(0, 90);

Your cam.setQuality is commented which means it will use the default values which translates into: vary the picture quality to keep the bitrate under 130kbits/s ( or 16384bytes/second).

130kbits/s is VERY LOW. Use cam.setQuality(0, 90) to tell Flash to use as much bandwidth as needed to keep the picture quality at 90.

See Camera.SetQuality documentation for more info.

Red5 version

If you're using Red5, you should make sure you're using at least Red5 1.0.3. It's the 1st version with video recording fixed. All previous versions had video recording broken, see this question for details.

Commercial solutions

You should also consider using a commercial solution like HDFVR or Pipe which handle everything including mobile and the conversion to .mp4 .

Regarding your "2 files" observation

but its making 2 files on the server and quality doesn't improve

Depending on the media server you're using you might get 1, 2 or more files.

Red5 for example will create 2 other files during the recording process (.ser and .info):

enter image description here

and, after the 1st playback, it will create another .meta file which holds the list of keyframe, their byte position and timestamp:

enter image description here

Here's the contents of such a .meta file:

<?xml version="1.0" encoding="UTF-8"?>
<FrameMetadata audioOnly="false" duration="24074" modified="1446217872000">
    <KeyFrame position="566" timestamp="39"/>
    <KeyFrame position="626" timestamp="40"/>
    <KeyFrame position="14705" timestamp="574"/>
    <KeyFrame position="14765" timestamp="575"/>
    ...
</FrameMetadata>
Remus Negrota
  • 634
  • 6
  • 13