1

We are utilizing Adobe FMS 4.5 to record video from users webcam. We are not live-broadcasting this video, we just want to capture it and save it on the server to do things with it later (attach to users' account, show as in-page content, etc).

We've written a robust capture application that streams up to the server, unpublishes correctly, and allows the user to view the video after it's finished unpublishing, etc. This does seem to work, in that it saves video files as we expect.

The problem is that those recorded videos seem to have a small gap at the beginning. It's considerably less than one second. We're talking maybe 5/100s to 1/10th of a second that has no video data. It really looks like there is no video keyframe at the very beginning of the video.

Now, this wouldn't normally be an issue - the video just begins a bit into the playback, and plays fine in most players. Problem is, we're allowing the users to trim videos arbitrarily later on with a different tool - a custom visual interface to FFmpeg. If they begin a video trim before that first keyframe there's an ugly grey mess in the final output because there is no visual data in the area where FFmpeg started cutting.

My first thought was, "Oh, I must need to attach the camera (differently | at a different point | on some callback | etc)". I played around with attaching the camera before calling publish, after NetStream.Publish.Start, etc, etc.

Am I missing something intrinsic, here? Or am I just working with the wrong idea, or do I misunderstand the process?

Of course, the answer I completely expect, but don't want is, "That's just how FMS does it." :) We could add a server-side process to remove the first XX bit of video, but it's arbitrary; we don't know how much to trim, and we don't want to risk losing any user data.

Here's a generalization of the code we used:

private function init():void
{
    var my_errors:Array = [];

    if ( !Camera.isSupported )
    {
        my_errors.push( 'camera is not supported' );
    }
    else
    {
        camera = Camera.getCamera();
        if ( !camera )
        {
            my_errors.push( 'no camera found' );
        }
        else if ( camera.muted )
        {
            Security.showSettings( SecurityPanel.PRIVACY );
        }
    }

    mic = Microphone.getMicrophone();
    if ( !mic )
    {
        my_errors.push( 'no microphone found' );
    }

    if ( my_errors.length )
    {
        this.fatal_error( my_errors );
        return;
    }

    camera.setMode( camera_width, camera_height, camera_fps, true );
    camera.setQuality( 0, camera_quality );

    netconnect = new NetConnection();
    netconnect.addEventListener( NetStatusEvent.NET_STATUS, net_status_handler );
    netconnect.connect( publish_url );
}
private function net_status_handler( ev:NetStatusEvent ):void
{
    switch ( ev.info.code )
    {
        case 'NetConnection.Connect.Success':
            trace( 'CONNECT: Connected to "' + publish_url + '"' );
            begin_stream();
        break;
    }
}
private function begin_stream():void
{
    if ( this.recording )
        return;
    this.recording = true;

    guid = GUID.create();

    netstream = new NetStream( netconnect );
    netstream.addEventListener( NetStatusEvent.NET_STATUS, net_stream_handler );
    netstream.attachCamera( camera );
    netstream.attachAudio( mic );
    netstream.publish( guid, 'record' );
}
Slobaum
  • 669
  • 7
  • 17

1 Answers1

0

Try listening to the StatusEvent.STATUS event on the Camera object. When the user clicks the 'Allow' button on the flash security dialog that pops up to ask permission for camera/microphone access - the StatusEvent will be triggered, with the code parameter being equal to 'Camera.Unmuted' - Put the 'publish' command on that event.

e.g.

function camStatus (evt:StatusEvent) {
   if (evt.code == 'Camera.Unmuted') {
      // Check if this is the first 'unmute' (as users can also unmute/mute later),
      // if so - publish on the netstream
   }
}
var camera:Camera = Camera.getCamera();
camera.addEventListener(StatusEvent.STATUS,camStatus);

If you publish before the user has allowed access for the camera - it will record empty frames as there is no video from the camera yet... You can also manage this on the server-level of course (call a server-side function from within the StatusEvent that will start the recording...)

Yuval A.
  • 5,849
  • 11
  • 51
  • 63