FLV文件的第一个Tag: onMetaData

onMetaData是FLV文件中的第一个Tag, 用来表示当前文件的一些基本信息: 比如视音频的编码类型id、视频的宽和高、文件大小、视频长度、创建日期等。

onMetaData基本信息

***onMetaData in Adobe Flash Video File Format Specification Version 10.1***

可以看出onMetaData是一个SCRIPTDATA类型的Tag.

用于表示视音频编码的两个属性: audiocodecidvideocodecid

  • audiocodecid
    音频的编码类型的id,如AACaudiocodecid=10
***audiocodecid list***
  • videocodecid
    视频的编码类型的id,如AVCvideocodecid=7
***videocodecid list***

SCRIPTDATA

SCRIPTDATA

可以看出在没有加密的情况下,SCRIPTDATAScriptTagBody组成, 主要包括NameValue两部分:

  • Name
    一个String类型的SCRIPTDATAVALUE

  • Value
    一个ECMA Array类型的SCRIPTDATAVALUE

SCRIPTDATA

SCRIPTDATAVALUE

***Part 1 of SCRIPTDATAVALUE***
***Part 2 of SCRIPTDATAVALUE***
  • SCRIPTDATASTRING
SCRIPTDATASTRING
  • SCRIPTDATAECMAARRAY
SCRIPTDATAECMAARRAY
  • ECMAArrayLength
    数组中的元素个数。
  • Variables
    SCRIPTDATAOBJECTPROPERTY的数组。
***SCRIPTDATAOBJECTPROPERTY***
***属性的格式***
  • List Terminator
    标志着SCRIPTDATAOBJECTPROPERTY数组的结束。
***SCRIPTDATAOBJECTEND***

示意代码

// CPxFLVMuxer.h
enum ePxAMFDataType
{ 
    AMF_NUMBER = 0, AMF_BOOLEAN, AMF_STRING, AMF_OBJECT,
    AMF_MOVIECLIP,      /* reserved, not used */
    AMF_NULL, AMF_UNDEFINED, AMF_REFERENCE, AMF_ECMA_ARRAY, AMF_OBJECT_END,
    AMF_STRICT_ARRAY, AMF_DATE, AMF_LONG_STRING, AMF_UNSUPPORTED,
    AMF_RECORDSET,      /* reserved, not used */
    AMF_XML_DOC, AMF_TYPED_OBJECT,
    AMF_AVMPLUS,        /* switch to AMF3 */
    AMF_INVALID = 0xff
};

char inline *put_byte( char *out_chPut, unsigned char in_uchVal )
{
    out_chPut[0] = in_uchVal;
    return out_chPut+1;
}

char inline *put_be16(char *out_chPut, unsigned short in_usVal )
{
    out_chPut[1] = in_usVal & 0xff;
    out_chPut[0] = in_usVal >> 8;
    return out_chPut+2;
}

char inline *put_be32(char *out_chPut, unsigned int in_unVal )
{
    out_chPut[3] = in_unVal & 0xff;
    out_chPut[2] = in_unVal >> 8;
    out_chPut[1] = in_unVal >> 16;
    out_chPut[0] = in_unVal >> 24;
    return out_chPut+4;
}

char inline *put_amf_string( char *out_chPut, const char *in_chBuf )
{
    uint16_t len = (uint16_t)strlen( in_chBuf );
    out_chPut=put_be16( out_chPut, len );
    memcpy(out_chPut,in_chBuf,len);
    return out_chPut+len;
}

char inline *put_amf_double( char *out_chPut, double in_dBuf )
{
    *out_chPut++ = AMF_NUMBER;  // type: Number
    {
        unsigned char *ci, *co;
        ci = (unsigned char *)&in_dBuf;
        co = (unsigned char *)out_chPut;
        co[0] = ci[7];
        co[1] = ci[6];
        co[2] = ci[5];
        co[3] = ci[4];
        co[4] = ci[3];
        co[5] = ci[2];
        co[6] = ci[1];
        co[7] = ci[0];
    }
    return out_chPut+8;
}

const int g_nMetaData = 1024 * 320;

// CPxFLVMuxer.cpp:
HRESULT CPxFLVMuxer::WriteOnMetaData()
{
    HRESULT hr = NS_NOERROR;

    ...

    //char chMetaData[g_nMetaData];
    char *chMetaData = new char[g_nMetaData];
    if (chMetaData == NULL)
    {
        ...
    }

    char *chMetaDataTemp = (char *)chMetaData;

    // SCRIPTDATASTRING
    chMetaDataTemp = put_byte(chMetaDataTemp, AMF_STRING);
    chMetaDataTemp = put_amf_string(chMetaDataTemp, "onMetaData");

    // SCRIPTDATAECMAARRAY
    chMetaDataTemp = put_byte(chMetaDataTemp, AMF_ECMA_ARRAY);

    // ECMAArrayLength : UI32 属性数组长度
    chMetaDataTemp = put_be32(chMetaDataTemp, 21); 

    // PropertyName
    chMetaDataTemp = put_amf_string(chMetaDataTemp, "MetaDataCreator"); 
    // Type:UI8 数据类型
    chMetaDataTemp = put_byte(chMetaDataTemp, AMF_STRING); 
    // ScriptDataValue: 数据
    chMetaDataTemp = put_amf_string(chMetaDataTemp, "created by ZL Guo @2016"); 

    // PropertyName
    chMetaDataTemp = put_amf_string(chMetaDataTemp, "hasKeyFrames"); 
    // Type:UI8 数据类型
    chMetaDataTemp = put_byte(chMetaDataTemp, AMF_BOOLEAN); 
    // ScriptDataValue: 数据
    chMetaDataTemp = put_byte(chMetaDataTemp, 0); 

    chMetaDataTemp = put_amf_string(chMetaDataTemp, "hasVideo");
    chMetaDataTemp = put_byte(chMetaDataTemp, AMF_BOOLEAN);
    chMetaDataTemp = put_byte(chMetaDataTemp, 1);

    chMetaDataTemp = put_amf_string(chMetaDataTemp, "hasAudio");
    chMetaDataTemp = put_byte(chMetaDataTemp, AMF_BOOLEAN);
    chMetaDataTemp = put_byte(chMetaDataTemp, 1);

    chMetaDataTemp = put_amf_string(chMetaDataTemp, "hasMatadata");
    chMetaDataTemp = put_byte(chMetaDataTemp, AMF_BOOLEAN);
    chMetaDataTemp = put_byte(chMetaDataTemp, 1);

    chMetaDataTemp = put_amf_string(chMetaDataTemp, "canSeekToEnd");
    chMetaDataTemp = put_byte(chMetaDataTemp, AMF_BOOLEAN);
    chMetaDataTemp = put_byte(chMetaDataTemp, 0);

    // PropertyName
    chMetaDataTemp = put_amf_string( chMetaDataTemp, "duration"); 
    // Type:UI8 数据类型 + ScriptDataValue: 数据
    chMetaDataTemp = put_amf_double( chMetaDataTemp, (double)0.0);

    chMetaDataTemp = put_amf_string( chMetaDataTemp, "width");
    chMetaDataTemp = put_amf_double( chMetaDataTemp, (double)m_sPxRecordFileProperty.aStreamProperty[m_nVideoStreamNum].nVideoWidth);

    chMetaDataTemp = put_amf_string( chMetaDataTemp, "height");
    chMetaDataTemp = put_amf_double( chMetaDataTemp, (double)m_sPxRecordFileProperty.aStreamProperty[m_nVideoStreamNum].nVideoHeight);

    chMetaDataTemp = put_amf_string( chMetaDataTemp, "videodatarate");
    chMetaDataTemp = put_amf_double( chMetaDataTemp, (double)m_sPxRecordFileProperty.aStreamProperty[m_nVideoStreamNum].nVideoBitrate);

    chMetaDataTemp = put_amf_string( chMetaDataTemp, "framerate");
    chMetaDataTemp = put_amf_double( chMetaDataTemp, (double)m_sPxRecordFileProperty.aStreamProperty[m_nVideoStreamNum].fVideoFrameRate);

    chMetaDataTemp = put_amf_string( chMetaDataTemp, "videocodecid");
    chMetaDataTemp = put_amf_double( chMetaDataTemp, (double)7.0);

    chMetaDataTemp = put_amf_string( chMetaDataTemp, "audiosamplerate");
    chMetaDataTemp = put_amf_double( chMetaDataTemp, (double)m_sPxRecordFileProperty.aStreamProperty[m_nVideoStreamNum].eAudioSamplesPerSecond);

    chMetaDataTemp = put_amf_string( chMetaDataTemp, "audiosamplesize");
    chMetaDataTemp = put_amf_double( chMetaDataTemp, (double)m_sPxRecordFileProperty.aStreamProperty[m_nVideoStreamNum].nAudioBitsPerSampleint);

    chMetaDataTemp = put_amf_string(chMetaDataTemp, "stereo");
    chMetaDataTemp = put_byte(chMetaDataTemp, AMF_BOOLEAN);
    chMetaDataTemp = put_byte(chMetaDataTemp, 1);

    chMetaDataTemp = put_amf_string( chMetaDataTemp, "audiocodecid");
    chMetaDataTemp = put_amf_double( chMetaDataTemp, (double)10.0);

    chMetaDataTemp = put_amf_string( chMetaDataTemp, "filesize");
    chMetaDataTemp = put_amf_double( chMetaDataTemp, (double)0.0);

    // List Terminator: SCRIPTDATAOBJECTEND 表示属性数组的结束
    // SCRIPTDATAOBJECTEND 即 0x00 0x00 0x09
    chMetaDataTemp = put_be24( chMetaDataTemp, 9);
    ...
}

References:

Adobe Flash Video File Format Specification Version 10.1

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,169评论 19 139
  • 实时消息协议---流的分块 版权声明: 版权(c)2009 Adobe系统有限公司。全权所有。 摘要: 本备忘录描...
    一个人zy阅读 1,987评论 0 9
  • http://www.jb51.net/article/29950.htm 文件后缀MIME备注 *.avivid...
    ink9979阅读 20,978评论 0 0
  • 教程一:视频截图(Tutorial 01: Making Screencaps) 首先我们需要了解视频文件的一些基...
    90后的思维阅读 4,840评论 0 3
  • 突然的想法…这念头萌生的好快!快得都没时间来考虑后果! 自从有了美颜相机,自己都变的不是自己了! 去年时这盘花眼看...
    语心语心阅读 283评论 0 1