前言

Windows Media Encoder是Microsoft Media Serial中的编码、转换工具,其支持将不同的文件转换成wmv/a格式,同时他也支持直接通过硬件设备(如声卡、摄像头等)采集数据,输出wmv/a格式。在输出方面wme支持直接存入文件,推送到wms(Microsoft Media Service),或推送到本地端口功能。然而推送到本地端口的数据并不完全符合asf 规范。

问题提出

在ASF Specfication中定义ASF文件的package的大小是固定的,这就导致有一部分(实际上是大部分)package达不到package的标准尺寸,因此需要一些填充字节来增长package的大小,使其符合header object中定义的package size。 我们知道,在wme的向本地推送数据时,实际上其数据包采用的是wms Http Streaming protocol,为了减少网络占用,wme推送http streaming数据时并没有推送这些填充字节,因为如果我们自己编写程序将http streaming数据转存到文件时,就必须对这些数据进行修正,这正在本文所关注的问题。

方案

首先,我们需要分析asf文件的头数据,找出其package的大小,然后,逐个分析每个package,如果其大小小于头中设定的大小,就需要进行修正。

对数据进行修复,就必须理解asf specification中的相关说明,根据5.2ASF Data package definition一节可知,数据包的组成如下:

我们所要做的就是根据Error Correction Data和Payload Parsing Information填充Padding Data,并修改data package中相应的数据(主要是Padding Length和Package Length字段)。实际上,Erro Corection Data都是存在的。

根据asf specification可知:

Error Correction Data

Payload parsing information

首先,我们要根据Error Correction Data的第一个字节(Error Correction Data Flags)了解Error Correction Data是否存在,以及其长度。检查Flags第8位是否为1(flags & 0x80 = 0x80),即可确定是否存在;如果存在,其低4位保存了Error Correcton Data Length(flags & 0x0f)。

然后跳过Error Correction Data,开始分析Payload parsing information。逐个分析Packet Length、Sequence、Padding Length的类型和大小。通常情况下,sequence是不存在的,其Length type flags中的值为00,Packet Length在某些情况下存在。分析方法如下:

Packet Length Type:flags & 0x60 >> 5

Sequence Type:flags & 0x06 >> 1

Padding Length Type: flags & 0x18 >>3

Type定义如下:

虽然这个图是针对Sequence的,但这个定义对三个字段的含义是相同。

经过以上分析,即可确定Packet Length字段、Padding Length字段是否存在,其类型是什么(BYTE、WORD、DWORD?),对应的修改Packet Length字段为asf header中定义的长度,然后修改Padding Length为asf header中的长度-本package的长度,在package后边添加填充字节即可。

示例代码(C#)

if (data.Length < AsfHeader.MaxPacketSize) //需要修正
                           {
                               int iPaddingOffset = 0;
                               int iPaddingLength = 0;
                               int iParserStart = 0;
                               //Error Correction
                               if ((data[0] & 0x80) == 0x80) //Error Correction 存在
                               {
                                   iPaddingOffset += (data[0] & 0x0f) + 1/*first byte.error correction flags*/;
                                   iParserStart = iPaddingOffset;
                               }
                               int c;
                               //取得Packet Length type
                               c = (data[iParserStart] & 0x60) >> 5;
                               switch (c)
                               {
                                   case 0: // does not exist
                                       break;
                                   case 1: // byte
                                       iPaddingOffset += 1;
                                       //fix length
                                       break;
                                   case 2: //word
                                       iPaddingOffset += 2;
                                       //fix length
                                       Array.Copy(BitConverter.GetBytes((ushort)mHeader.AsfHeader.MaxPacketSize), 0,data,iPaddingOffset,2);
                                       break;
                                   case 3: //dword
                                       iPaddingOffset += 4;
                                       //fix length
                                       Array.Copy(BitConverter.GetBytes(mHeader.AsfHeader.MaxPacketSize), 0, data, iPaddingOffset -2, 4);
                                       break;
                               }
                               //取得Sequence type
                               c = (data[iParserStart] & 0x06) >> 1;
                               switch (c)
                               {
                                   case 0: // does not exist
                                       break;
                                   case 1: // byte
                                       iPaddingOffset += 1;
                                       break;
                                   case 2: //word
                                       iPaddingOffset += 2;
                                       break;
                                   case 3: //dword
                                       iPaddingOffset += 4;
                                       break;
                               }
                               //取得Padding Length type
                               c = (data[iParserStart] & 0x18) >> 3;
                               switch (c)
                               {
                                   case 0: // does not exist
                                       break;
                                   case 1: // byte
                                       iPaddingLength = 1;
                                       break;
                                   case 2: //word
                                       iPaddingLength = 2;
                                       break;
                                   case 3: //dword
                                       iPaddingLength = 4;
                                       break;
                               }
                               int iPaddings = (int)(AsfHeader.MaxPacketSize - data.Length);
                               iPaddingOffset += 2;//skip payload parser information
                               switch (iPaddingLength)
                               {
                                   case 0:
                                       break;
                                   case 1:
                                       data[iPaddingOffset] = (byte)iPaddings;
                                       break;
                                   case 2:
                                       Array.Copy(BitConverter.GetBytes((ushort)iPaddings), 0, data, iPaddingOffset, iPaddingLength);
                                       break;
                                   case 3:
                                       Array.Copy(BitConverter.GetBytes((uint)iPaddings), 0, data, iPaddingOffset, iPaddingLength);
                                       break;
                               }
                               chunk.Data = new byte[AsfHeader.MaxPacketSize];
                               //chunk.Data.Initialize();
                                Array.Copy(data, chunk.Data, data.Length);
                                chunk.Length = (ushort)chunk.Data.Length;
                           }
                           else
                           {
                               chunk.Data = data;
                           }

参考资料

ASF Specification

转载于:https://www.cnblogs.com/Ankh/archive/2007/08/09/849019.html

修正wme输出的ASF流数据相关推荐

  1. 输入H.264流,输出封装格式流

    //H264ToContainer_Win32.h extern "C" {//@param format_name 输出流的格式名//@param r_frame_rate 输入 ...

  2. 大数据-07-Spark之流数据

    摘自 http://dblab.xmu.edu.cn/blog/1084-2/ 简介 DStream是Spark Streaming的编程模型,DStream的操作包括输入.转换和输出. Spark ...

  3. 基于matplotlib.animation和python的流数据动态监控原型

    流数据动态监控原型的内容概述 开发环境:Python3.6 代码行数:不到40行代码 代码风格:详细注解 代码特点:一定能跑起来 附加资料:带详细注释的九个animation实例 Decay The ...

  4. 11 编程指南_流数据

    Flink 的流数据 API 编程指南 Flink 的流数据处理程序是常规的程序 ,通过再流数据上,实现了各种转换 (比如 过滤, 更新中间状态, 定义窗口, 聚合).流数据可以来之多种数据源 (比如 ...

  5. 通过ffmpeg实时读取宇视摄像头的高清帧流数据,并保存4张图片进行4合一照片的生成。

    通过ffmpeg实时读取宇视摄像头的高清帧流数据,并保存4张图片进行4合一照片的生成. FFmpeg视频解码过程 通常来说,FFmpeg的视频解码过程有以下几个步骤: 注册所支持的所有的文件(容器)格 ...

  6. 实时行情难处理?睿凝资本选择DolphinDB解决流数据难题

    睿凝资本 CEO 王睿.CTO Jack 最初了解到DolphinDB是知乎的一条测评贴.作为KDB+的多年老用户,我对于这家对标KDB+.测评结果优秀的国产时序数据库非常感兴趣.读帖不久,前公司恰好 ...

  7. 黑马程序员_JAVA之IO流的(转换流,数据输入输出流等)

    ------- android培训.java培训.期待与您交流!---------- IO流: 笔记内容:转换流,字节输入输出流,数据输入输出流,内存操作流,随机访问流 打印流,对象序列化流,Prop ...

  8. 解决 HttpServletRequest 流数据不可重复读

    背景介绍 甲方客户的生产系统,有安全风险预警和安全事件快速溯源要求,需要做一套日志管理规范. 要求我们接入的系统,要对用户登录.注册.密码修改等重要场景,严格按照提供的格式,输出相应的日志. 后续通过 ...

  9. 树莓派4B摄像头推出流数据

    树莓派4B摄像头推出流数据 树莓派摄像头调试 排线连接 摄像头权限激活 测试摄像头功能 树莓派原生推http流 使用vlc打开网络串流 树莓派原生推rtsp流 使用vlc打开网络串流 启动异常处理 f ...

最新文章

  1. 主席树 | 莫队 ---- Codeforces Round #716 (Div. 2) D. Cut and Stick [主席树or莫队优化] 区间众数问题(静态)
  2. 找最大公约数和最小公倍数(c语言实现)
  3. bitnami-redmine Apache服务启动不起来
  4. 了解JVM运行时的内存分配
  5. php实现注册登陆验证
  6. 红帽Linux7怎么修改网卡名称,新安装的Centos 7系统怎么将网卡名称改为eth0?
  7. OpenStack精华问答 | OpenStack的网络类型有哪些?
  8. Java中遭遇NaN
  9. appassembler-maven-plugin插件打包本地依赖的jar
  10. go1.5源代码安装
  11. Golang 中map与GC“纠缠不清”的关系
  12. 织梦后台登陆不上提示验证码不正确
  13. 手机uc7.2java版下载_UC浏览器 JAVA
  14. 双因素认证令牌_安全令牌:防止双因素令牌认证攻击
  15. 20220609 C++版的ends_with
  16. 给技术经理找了几款Docker开源镜像仓库,为什么经理选中了Sonatype Nexus(下)
  17. 网络安全 - 一名合格的Web安全工程师之成长路径
  18. vue 环信im 发送图片、接收图片
  19. CSS transform中的rotate设置旋转中心
  20. ad hoc java_Java并发编程--线程封闭(Ad-hoc封闭 栈封闭 ThreadLocal)

热门文章

  1. 基于pygame的射击小游戏制作(五)绘制开始按钮
  2. numpy(4)-计算数据异常值
  3. 【数学基础】运筹学:拉格朗日乘子法和KKT条件(上)
  4. 【算法】吴忠强:刷LeetCode的正确姿势!
  5. 【深度学习】李沐《动手学深度学习》的PyTorch实现已完成
  6. Ubuntu18.04+CUDA10.2 深度学习开发环境配置指南
  7. 【实战】用机器学习来提升你的用户增长:(三、预测客户的终生价值)
  8. 【实战】使用pyecharts绘制词云图-淘宝商品评论展示
  9. AAAI2021论文合集汇总!(持续更新)
  10. 网易云信荣获2021年度智慧教育典型案例奖项,并入选《智慧教育发展及产业图谱研究报告》...