actionscript-3flashffmpegairnetstream

AS3 NetStream AppendBytes Seek issue


I'm having trouble with NetStream in AS3. The project I am working on allows users to browse a video (locally) and play it back. The issue I am having is that netStream.seek(0); from what I can tell it doesn't do anything, although I get inside a NetStatusEvent function and NetStream.Seek.Notify is triggered. I'm using NativeProcess and the following function is this makes any difference.

public function ProgressEventOutputHandler(e:ProgressEvent):void {
    videoByteArray = new ByteArray();
    nativeProcess.standardOutput.readBytes(videoByteArray, 0, nativeProcess.standardOutput.bytesAvailable);
    netStream.appendBytes(videoByteArray);
}

Am I missing something here? I am pausing netStream before using netStream.seek(0);.

EDIT:

In an attempt to fix this issue I followed the instructions by VC.One I've done the following:

I have changed nothing else and now the video will not load. If I allow a new ByteArray to be created inside the ProgressEventOutputHandler function the video does load again.


Solution

  • Short Version :

    Try the code I pasted here: Github Snippet link

    Long version :

    this one's kinda long but hope it helps once and for all... Don't worry about the brick wall thing, walls are made to be smashed. To keep you inspired, check out some in-house demos from the VC:One labs using appendBytes :

    PS: I'll be using URLStream method as that's a more useful answer to those loading local or online files. You could change from urlstream.progressEvent to your usual nativeProcess.progressEvent.
    I know FFMPEG but only used AIR for making Android apps. So for this AIR/FFMPEG connection you know more than me.

    Also this answer assumes you're using FLV with MPEG H.264 video & MP3 or AAC audio.

    ffmpeg -i input.mp4 -c:v copy -c:a mp3 -b:a 128k -ac 2 -ar 44100 FLV_with_MP3.flv

    This assumption matters because it affects what kind of bytes we look for. In the case of the above FLV with a H.264 video and AAC or MP3 audio we can expect the following (when seeking) :

    1) Bytes copying and checking values :

    You are looking for bytes that represent a video "tag". Apart from the Metadata tag, you can now expect "tag" to mean a container of an audio or video frame. There are two ways to get tag bytes into your "temporary byte array" (we'll name it as temp_BA ).

    Readbytes explained : tells Source to read its bytes into Target. Source will read forwards up to the length from its current offset (position). Go to correct Source position before reading onwards...

    source_BA.readBytes( into Target_BA, Pos within Target_BA, length of bytes required );

    After the above line executes, Source position will now have moved forward to account for the new length travelled. (formula : Source new Pos = previousPos + BytesLengthRequired).

    Writebytes explained : tells Target to duplicate a range of bytes from Source. Is fast since copying from already-known information (from Source). Target writes onwards from its current position...

    target_BA.writeBytes( from source_BA, Pos within source_BA, length of bytes required );

    After the above line executes, note that both Source and Target positions are unchanged.

    Use above methods to get required tag bytes into temp_BA from a specific source_BA.position = x.

    To check any byte (its value), use the methods below to update some variable of int type:

    note : Don't confuse .readByte(); which extracts a numerical value (of byte) with the similar sounding .readBytes() which copies a chunk of bytes to another byte array.

    2) Finding A Video KeyFrame (or I-frame) :

    [ illustration image of Video TAG with Keyframe H264/AAC ]

    To find a video keyframe

    note : For reading 3 bytes of Tag Size I will show a custom converting bytes_toInt() function (since processors read either 1, 2 or 4 bytes at once for integers, reading 3 bytes here is an akward request).

    Searching tip : Tags always follow each other in a trail. We can seek faster by also checking if bytes are for a non-keyframe (P frame) video tag or even some audio tag. If so then we check that particular tag size and now increment our xPos to jump this new length. This way we can skip by whole tag sizes not just by single bytes. Stopping only when we have a keyframe tag.

    3) Playback From A Video KeyFrame :

    When you think about it, play is simply like an auto-seek going on a frame by frame basis. Where the expected speed of getting each next frame is defined by the video's encoded framerate.

    So your playback function can simply be a Timer that gets X-amount of video tags (frames) every second (or 1000 milisecs). You do that as example my_Timer = new Timer ( video_FPS ). When the timer runs and reaches each FPS slice of a second it will run the append_PLAY(); function which in turn runs a get_frame_Tag(); function.

    The play function acts as a middle-man function to manage things without cluttering the get frame function with If statements etc. Managing things means for example checking that there are enough bytes downloaded to even begin getting a frame according to Tag Size.

    4) Source Code For A Working Example :

    Code is too long.. see this link below: https://gist.github.com/Valerio-Charles-VC1/657054b773dba9ba1cbc

    Hope it helps. VC