第1年1月10日 flv格式

1.雷神读flv文件代码,https://blog.csdn.net/leixiaohua1020/article/details/42104945
读flv文件jump over9个字节,再jump over4个字节。再读type,datalength,timestamp,streamid。

还是要对照协议看。

The FLV header

9个字节的文件头

 
Field             Type    Comment
Signature         UI8     Signature byte always 'F' (0x46)
Signature         UI8     Signature byte always 'L' (0x4C)
Signature         UI8     Signature byte always 'V' (0x56)
Version           UI8     File version (for example, 0x01 for FLV version 1)
TypeFlagsReserved UB [5]  Shall be 0
TypeFlagsAudio    UB [1]  1 = Audio tags are present
TypeFlagsReserved UB [1]  Shall be 0
TypeFlagsVideo    UB [1]  1 = Video tags are present
DataOffset        UI32    The length of this header in bytes
The FLV File Body

4个字节的PreviousTagSize0,接着是FLVTAG,循环

Field            Type    Comment
PreviousTagSize0 UI32    Always 0
Tag1             FLVTAG  First tag
PreviousTagSize1 UI32    Size of previous tag, including its header, in bytes. 
For FLV version 1, this value is 11 plus the DataSize of the previous tag. Tag2 FLVTAG Second tag ...
FLV Tag
读type,datalength,timestamp,streamid。type==8是音频,type==9是视频。
 
VideoTagHeader

结合前文《librtmp发送h264》  ,SendH264Packet函数,SendVideoSpsPps函数就是这样组包的。

    //packet attributes
    uint32_t type=0;            
    uint32_t datalength=0;        
    uint32_t timestamp=0;        
    uint32_t streamid=0;            

    FILE*fp=NULL;
    fp=fopen("cuc_ieschool.flv","rb");
    if (!fp){
        RTMP_LogPrintf("Open File Error.
");
        CleanupSockets();
        return -1;
    }

    //jump over FLV Header
    fseek(fp,9,SEEK_SET);    
    //jump over previousTagSizen
    fseek(fp,4,SEEK_CUR);    
    start_time=RTMP_GetTime();
    while(1)
    {
        if((((now_time=RTMP_GetTime())-start_time)
              <(pre_frame_time)) && bNextIsKey){    
            //wait for 1 sec if the send process is too fast
            //this mechanism is not very good,need some improvement
            if(pre_frame_time>lasttime){
                RTMP_LogPrintf("TimeStamp:%8lu ms
",pre_frame_time);
                lasttime=pre_frame_time;
            }
            Sleep(1000);
            continue;
        }
        
        //not quite the same as FLV spec
        if(!ReadU8(&type,fp))    
            break;
        if(!ReadU24(&datalength,fp))
            break;
        if(!ReadTime(&timestamp,fp))
            break;
        if(!ReadU24(&streamid,fp))
            break;

        if (type!=0x08&&type!=0x09){
            //jump over non_audio and non_video frame,
            //jump over next previousTagSizen at the same time
            fseek(fp,datalength+4,SEEK_CUR);
            continue;
        }
        
        if(fread(packet->m_body,1,datalength,fp)!=datalength)
            break;

        packet->m_headerType = RTMP_PACKET_SIZE_LARGE; 
        packet->m_nTimeStamp = timestamp; 
        packet->m_packetType = type;
        packet->m_nBodySize  = datalength;
        pre_frame_time=timestamp;

        if (!RTMP_IsConnected(rtmp)){
            RTMP_Log(RTMP_LOGERROR,"rtmp is not connect
");
            break;
        }
        if (!RTMP_SendPacket(rtmp,packet,0)){
            RTMP_Log(RTMP_LOGERROR,"Send Error
");
            break;
        }

        if(!ReadU32(&preTagsize,fp))
            break;
            
        if(!PeekU8(&type,fp))
            break;
        if(type==0x09){
            if(fseek(fp,11,SEEK_CUR)!=0)
                break;
            if(!PeekU8(&type,fp)){
                break;
            }
            if(type==0x17)
                bNextIsKey=1;
            else
                bNextIsKey=0;

            fseek(fp,-11,SEEK_CUR);
        }
    }                

    RTMP_LogPrintf("
Send Data Over
");
    
    if(fp)
        fclose(fp);

https://blog.csdn.net/leixiaohua1020/article/details/42104945

https://depthlove.github.io/2015/11/13/flv-analysis-in-rtmp-live-play/

https://blog.csdn.net/yeyumin89/article/details/7932368

2.avc

configurtaionVersion: 第一字段,占8位。其值始终为1。
AVCProfileIndication: 这个字段也占8位,填写AVC的profile. 我们一般接触比较多的profile. 有Baseline Profile(66), Main Profile(77), Extended Profile(88), High Profile(100)。这个值就是直接去AVC Sps的 profile_idc字段的值。
profile_compatibility: 这个字段就是Sps 中哪些Constraints_set 的值。所以直接去Sps第二个字节。
AVCLevelIndication: 这个字段就是Sps中的level_idc字段的值。
所以可以看出,就是直接Copy了Sps的前三个字节。
lengthSizeMinusOne:指示AVC视频中NALUnitLength字段的字节长度。 比如NALUintlength字段我们用4字节。那么这里就是4-1 = 3; 一般我们NALUingLenth字段就固定为4了,所以这个字段就是3: ‘11’b。
numOfSequenceParameterSets: 指示在这个AVCDecoderConfigurtaionRecord中包含的Sps的个数。一般就一个咯,所以取值为’00001’b。
sequenceParameterSetLength: 单个Sps的长度。
spsquenceParameterSetNALUint:Sps的实际内容。
numOfPictureParameterSets: pps的个数。一般就是1.
pictureParameterSetLength: pps的长度。注意字节序。大端
pictureParamterSetNALUint: pps的实际内容。
如果此时AVCPacketType==1.且在第一个TAG中 lengthSizeMinusOne被设置为3(4-1)。那么此时的Data字段将在实际的NALUint数据前面加上一个4字节的NALUintLength字段。注意为大端模式。然后才是实际的NALUint的数据

https://blog.csdn.net/y_z_hyangmo/article/details/79208275

3.rtmp消息分块

 +--------------+----------------+--------------------+--------------+
 | Basic Header | Message Header | Extended Timestamp |  Chunk Data  |
 +--------------+----------------+--------------------+--------------+
 |                                                    |
 |<------------------- Chunk Header ----------------->|
                            Chunk Format
  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                          timestamp            | message length|
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |      message length (cont)    |message type id| msg stream id |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |          message stream id (cont)             |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                Chunk Message Header - Type 0

https://blog.csdn.net/tanningzhong/article/details/109787281

原文地址:https://www.cnblogs.com/javastart/p/14260174.html