flvdec.c flv_read_header flv_read_packet解析

/*单位bytes
 ---------------------------------------------------------------
|signature总为0x46,0x4c,0x66(FLV)|version(1)|Flags|HeaderSize(9)|
 ---------------------------------------------------------------
|              3                 |    1     |  1  |      4      |
 ---------------------------------------------------------------
*/
static int flv_read_header(AVFormatContext *s)
{
    int flags;
    FLVContext *flv = s->priv_data;
    int offset;
    int pre_tag_size = 0;

    /* Actual FLV data at 0xe40000 in KUX file */
    if(!strcmp(s->iformat->name, "kux"))
        avio_skip(s->pb, 0xe40000);

    avio_skip(s->pb, 4); // 固定3个字节的'F','L','V'加上一个字节的version
    flags = avio_r8(s->pb); // 1字节的flag

    flv->missing_streams = flags & (FLV_HEADER_FLAG_HASVIDEO | FLV_HEADER_FLAG_HASAUDIO); // 判断是否既有音频又有视频,视频0x1,音频0x4

    s->ctx_flags |= AVFMTCTX_NOHEADER;

    offset = avio_rb32(s->pb); // flv的header长度,固定4个字节
    avio_seek(s->pb, offset, SEEK_SET);

    /* Annex E. The FLV File Format
     * E.3 TheFLVFileBody
     *     Field               Type    Comment
     *     PreviousTagSize0    UI32    Always 0
     * */
    pre_tag_size = avio_rb32(s->pb); // previous tag size
    if (pre_tag_size) {
        av_log(s, AV_LOG_WARNING, "Read FLV header error, input file is not a standard flv format, first PreviousTagSize0 always is 0\n");
    }

    s->start_time = 0;
    flv->sum_flv_tag_size = 0;
    flv->last_keyframe_stream_index = -1;

    return 0;
}
static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
{
    FLVContext *flv = s->priv_data;
    int ret, i, size, flags;
    enum FlvTagType type;
    int stream_type=-1;
    int64_t next, pos, meta_pos;
    int64_t dts, pts = AV_NOPTS_VALUE;
    int av_uninit(channels);
    int av_uninit(sample_rate);
    AVStream *st    = NULL;
    int last = -1;
    int orig_size;

retry:
    /* pkt size is repeated at end. skip it */
    /*
    长度单位Bytes
    ----------------------------------------------------------
    |Type|DataSize|TimeStamp|Timestamp_ex|StreamID|           |
    ----------------------------------------------|  tagData  |
    | 1  |   3    |    3    |     1      |   3    |           |
    ----------------------------------------------------------
    */
    pos  = avio_tell(s->pb);
    type = (avio_r8(s->pb) & 0x1F); // 读取tag head第一个字节,tag的类型音频(0x8),视频(0x9),脚本(0x12)
    orig_size =
    size = avio_rb24(s->pb); // 第2到4字节是数据区的长度 tag data size
    flv->sum_flv_tag_size += size + 11; // 数据的长度 + tag header的长度11
    dts  = avio_rb24(s->pb); // timestamp时间戳,单位是ms,类型为0x12则时间戳为0,时间戳控制着文件播放的速度,可以根据音视频的帧类型设置
    dts |= (unsigned)avio_r8(s->pb) << 24; // timestamp_ex,时间戳的一个扩展,时间戳长度不够的时候使用
    av_log(s, AV_LOG_TRACE, "type:%d, size:%d, last:%d, dts:%"PRId64" pos:%"PRId64"\n", type, size, last, dts, avio_tell(s->pb));
    if (avio_feof(s->pb))
        return AVERROR_EOF;
    avio_skip(s->pb, 3); /* stream id, always 0 */
    flags = 0;

    if (flv->validate_next < flv->validate_count) {
        int64_t validate_pos = flv->validate_index[flv->validate_next].pos;
        if (pos == validate_pos) {
            if (FFABS(dts - flv->validate_index[flv->validate_next].dts) <=
                VALIDATE_INDEX_TS_THRESH) {
                flv->validate_next++;
            } else {
                clear_index_entries(s, validate_pos);
                flv->validate_count = 0;
            }
        } else if (pos > validate_pos) {
            clear_index_entries(s, validate_pos);
            flv->validate_count = 0;
        }
    }

    if (size == 0) {
        ret = FFERROR_REDO;
        goto leave;
    }

    next = size + avio_tell(s->pb); // 下一个tag的位置

    if (type == FLV_TAG_TYPE_AUDIO) {
        /*单位bit
         ------------------------------------------
        |音频编码类型|采样率|样点位宽|声道数|
         --------------------------------| 音频数据
        |    4      | 2   |   1    |  1  |
         -----------------------------------------
        */
        stream_type = FLV_STREAM_TYPE_AUDIO;
        flags    = avio_r8(s->pb);
        size--;
    } else if (type == FLV_TAG_TYPE_VIDEO) {
        /*单位bit
         ------------------------------------------
        |帧类型|视频编码类型|
         -----------------| 视频数据
        |  4  |  4(低位)   |
         -----------------------------------------
        */
        stream_type = FLV_STREAM_TYPE_VIDEO;
        flags    = avio_r8(s->pb);
        size--;
        if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD)
            goto skip;
    } else if (type == FLV_TAG_TYPE_META) {
        /*单位bytes
         ---------------------------------------------------
        |AMF1("onMetaData")占13字节|AMF2("width,height...")|
        AMF1:
         -----------------------------------------------------
        |AMF包类型(0x2)|标识字符串长度(0xA)|字符串("onMetaData")|
         ----------------------------------------------------
        |      1       |        2        |          10        |
         -----------------------------------------------------
        AMF2:
         -----------------------------------------------------------------------------------
        |包类型(0x8)|数组元素个数|0x0|数组元素名长度|数组元素名(字符串'\0'结尾)|数组元素值(double)|
         -----------------------------------------------------------------------------------
        |     1    |    4      | 1 |     1       |                        |        8        |
         -----------------------------------------------------------------------------------
        元素名:
        duration : 时长
        width : 视频宽度
        height : 视频高度
        videodatarate : 视频码率
        framerate : 视频帧率
        videocodecid : 视频编码方式
        audiosamplerate : 音频采样率
        audiosamplesize : 音频采样精度
        stereo : 是否为立体声
        audiocodecid : 音频编码方式
        filesize : 文件大小
        */
        stream_type=FLV_STREAM_TYPE_SUBTITLE;
        if (size > 13 + 1 + 4) { // Header-type metadata stuff
            int type;
            meta_pos = avio_tell(s->pb);
            type = flv_read_metabody(s, next);
            if (type == 0 && dts == 0 || type < 0) {
                if (type < 0 && flv->validate_count &&
                    flv->validate_index[0].pos     > next &&
                    flv->validate_index[0].pos - 4 < next) {
                    av_log(s, AV_LOG_WARNING, "Adjusting next position due to index mismatch\n");
                    next = flv->validate_index[0].pos - 4;
                }
                goto skip;
            } else if (type == TYPE_ONTEXTDATA) {
                avpriv_request_sample(s, "OnTextData packet");
                return flv_data_packet(s, pkt, dts, next);
            } else if (type == TYPE_ONCAPTION) {
                return flv_data_packet(s, pkt, dts, next);
            } else if (type == TYPE_UNKNOWN) {
                stream_type = FLV_STREAM_TYPE_DATA;
            }
            avio_seek(s->pb, meta_pos, SEEK_SET);
        }
    } else {
        av_log(s, AV_LOG_DEBUG,
               "Skipping flv packet: type %d, size %d, flags %d.\n",
               type, size, flags);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值