加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

actionscript-3 – AS3 NetStream AppendBytes寻求问题

发布时间:2020-12-15 07:28:04 所属栏目:百科 来源:网络整理
导读:我在AS3中遇到NetStream问题.我正在开发的项目允许用户浏览视频(本地)并播放.我遇到的问题是netStream.seek(0);从我可以告诉它没有做任何事情,虽然我进入NetStatusEvent函数并触发NetStream.Seek.Notify.我正在使用NativeProcess,以下功能使这有任何区别. pu
我在AS3中遇到NetStream问题.我正在开发的项目允许用户浏览视频(本地)并播放.我遇到的问题是netStream.seek(0);从我可以告诉它没有做任何事情,虽然我进入NetStatusEvent函数并触发NetStream.Seek.Notify.我正在使用NativeProcess,以下功能使这有任何区别.

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

我在这里错过了什么吗?我在使用netStream.seek(0);之前暂停netStream.

编辑:

为了解决这个问题,我按照VC的说明进行操作.我已经完成了以下操作:

>移动了videoByteArray = new ByteArray();到我的init函数,还创建了tempVideoByteArray = new ByteArray();在这个功能.
>更新我的ProgressEventOutputHandler函数,使其不再为videoByteArray创建新的ByteArray并更改此行 – nativeProcess.standardOutput.readBytes(videoByteArray,videoByteArray.length,nativeProcess.standardOutput.bytesAvailable);

我没有改变任何其他内容,现在视频无法加载.如果我允许在ProgressEventOutputHandler函数内创建新的ByteArray,则视频会再次加载.

解决方法

精简版 :

试试我粘贴的代码:Github Snippet链接

长版:

这个有点长,但希望它一劳永逸……不要担心砖墙的东西,墙壁被打碎.为了让您受到启发,请查看VC的一些内部演示:使用appendBytes的一个实验室:

> MP4 Seeking Experiment:研究appendBytes帧数据访问和时间/搜索处理.实时帧字节仅使用AS3代码从MP4转换为FLV格式.
> Speed Adjust of Audio & Video:用于视频分离中的实时MP3音频影响实验.需要带音频轨道中MP3数据的MP4 / FLV文件.
> Synchronised Video Frames:用于以相同帧编号显示的多个视频.

PS:我将使用URLStream方法,因为这对那些加载本地或在线文件的人来说是一个更有用的答案.您可以从urlstream.progressEvent更改为常用的nativeProcess.progressEvent.
我知道FFMPEG,但只使用AIR制作Android应用程序.所以对于这个AIR / FFMPEG连接,你比我更了解.

此答案假设您正在使用FLV和MPEG H.264视频& MP3或AAC音频.

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

这个假设很重要,因为它影响我们寻找的字节类型.
对于具有H.264视频和AAC或MP3音频的上述FLV,我们可以期待以下(寻求时):

>由于这是MPEG,第一个视频标签将保存AVC解码器配置字节,第一个音频标签保存音频特定配置字节.此数据不是实际的媒体帧,而是简单地打包为音频/视频标签. MPEG播放需要这些.可以在MP4容器内的STSD元数据条目(MOOV atom)中找到相同的字节.现在,下一个找到的视频标签将(或应该)成为视频的实际第一帧.
>视频关键帧:从0x09开始,接下来的第11个字节是0x17&第12个字节是0x01
> Audio TAG AAC:从0x08开始,接下来的第11个字节是0xAF&第12个字节是0x01
> Audio TAG MP3:从0x08开始,接下来的第11个字节是0x2F&第12个字节是0xFF

1)字节复制和检查值:

您正在寻找代表视频“标签”的字节.除了元数据标记之外,您现在可以期望“标记”表示音频或视频帧的容器.将标记字节放入“临时字节数组”有两种方法(我们将其命名为temp_BA).

> ReadBytes(slow):在source_BA中的开始/结束范围内提取单个字节值
> WriteBytes(快速):从source_BA即时复制字节的开始/结束范围

Readbytes解释:告诉Source将其字节读入Target.源将从其当前偏移(位置)向前读取长度.在阅读之前去正确的Source位置…
source_BA.readBytes(进入Target_BA,Target_BA内的Pos,所需的字节长度);
在执行上述行之后,Source位置现在将向前移动以考虑新行程的长度. (公式:来源新Pos = previousPos BytesLengthRequired).

Writebytes解释:告诉Target从Source复制一系列字节.从已知信息(来自Source)复制后速度很快.目标从当前位置开始向前写…
target_BA.writeBytes(来自source_BA,source_BA中的Pos,所需的字节长度);
执行上述行后,请注意Source和Target位置不变.

使用上述方法从特定的source_BA.position = x获取所需的标记字节到temp_BA.

要检查任何字节(其值),请使用以下方法更新int类型的某些变量:

>阅读one-byte value:使用my_Integer = source_BA.readByte();
>阅读two-byte value:使用my_Integer = source_BA.readUnsignedShort();
>阅读four-byte value:使用my_Integer = source_BA.readUnsignedInt();
> eight-byte value的变量号:使用my_Number = source_BA.readDouble();

注意:不要混淆.readByte();它使用类似的声音.readBytes()提取一个数值(字节),它将一块字节复制到另一个字节数组.

2)查找视频KeyFrame(或I帧):

[视频标签与关键帧H264 / AAC的插图图片]

要查找视频关键帧

>从起始偏移量开始,使用while循环现在通过搜索每个字节的字节前进[07]的“9”(十六进制:0x09),当发现我们进一步检查前面的字节以确认它确实是一个真正的关键帧而不只是随机出现的“9”.
>在H.264视频编解码器的情况下,在正确的“9”字节位置(xPos),我们期望第11&前面的第12个字节总是分别为“17”和“01”.
>如果这是== true,那么我们检查三个Tag Size字节,并将15加到此整数中,以获得预期从Source写入Target(temp_BA)的总字节长度.我们已经添加了15来说明之前的11个字节以及预期的TAG DATA之后的4个字节.标签结尾处的这4个字节是“上一个标记大小”,这个数量实际上包括11个前面的字节,但不计算这些结束4个字节本身.
>我们告诉temp_BA从“9”字节(xPos)的pos开始写入Source(你的videoByteArray)的字节,长度为“Tag Size”15.你现在已经提取了一个MPEG关键帧.示例:temp_BA.writeBytes(videoByteArray,int(xPos),int(TAG_size));
>现在可以使用以下内容附加此带有关键帧标记的temp_BA:
示例:netStream.appendBytes(temp_BA); //显示单个框架

注意:为了读取3个字节的标签大小,我将显示一个自定义转换bytes_toInt()函数(因为处理器一次读取1,2或4个字节的整数,这里读取3个字节是一个令人讨厌的请求).

搜索提示:标记始终在跟踪中互相跟随.我们可以通过检查字节是否用于非关键帧(P帧)视频标签甚至某些音频标签来更快地寻求.如果是这样,那么我们检查特定的标签大小,现在增加我们的xPos以跳过这个新的长度.这样我们就可以跳过整个标签大小而不仅仅是单个字节.仅在我们有关键帧标记时停止.

3)从视频关键帧播放:

当你考虑它时,游戏就像一个逐帧的自动搜索.获得每个下一帧的预期速度由视频的编码帧速率定义.

所以你的播放功能可以简单地是一个每秒钟(或1000毫秒)获得X量视频标签(帧)的定时器.你这样做的例子是my_Timer = new Timer(video_FPS).当计时器运行并到达每秒的每个FPS切片时,它将运行append_PLAY();函数反过来运行get_frame_Tag();功能.

> NS.seek(0):将NetStream置于“搜索模式”. (数字无关紧要,但必须存在于命令中).任何“前帧”缓冲区都被清除,它们将不会(图像)帧更新,直到..
> RESET_SEEK:结束“搜索模式”,现在允许图像更新.使用RESET_SEEK命令后附加的第一个标记必须是带有视频关键帧的标记. (对于仅音频,这可以是任何标签,因为从技术上讲,所有音频标签都是音频关键帧)
> END_SEQUENCE :(对于MPEG H.264)播放任何剩余的“前帧”(排出缓冲区).一旦耗尽,您现在可以附加任何类型的视频标签.记住H.264期望前移时间戳,如果你看到f ** ked up像素,那么你的下一个标签时间戳是错误的(太高或太低).如果你只附加一帧(海报图片?),你可以使用END_SEQUEMCE来排空缓冲区并显示一帧(无需等待缓冲区首先填充x量的帧)…

play函数作为一个中间函数来管理事物而不会使用if语句等混淆get frame函数.管理事物意味着例如检查是否有足够的字节下载甚至根据Tag Size开始获取帧.

4)工作示例的源代码:

代码太长了..请参阅下面的link:
https://gist.github.com/Valerio-Charles-VC1/657054b773dba9ba1cbc

希望能帮助到你.虚电路

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读