您的位置:首页 > 财经 > 金融 > 手机设计装修图的app_广州app开发公司排名十强_短视频代运营方案策划书_网站设计与建设

手机设计装修图的app_广州app开发公司排名十强_短视频代运营方案策划书_网站设计与建设

2024/11/19 2:45:26 来源:https://blog.csdn.net/u014552102/article/details/142568846  浏览:    关键词:手机设计装修图的app_广州app开发公司排名十强_短视频代运营方案策划书_网站设计与建设
手机设计装修图的app_广州app开发公司排名十强_短视频代运营方案策划书_网站设计与建设

一、引言

在《音视频入门基础:FLV专题(3)——FLV header简介》中对FLV格式的FLV header进行了简介,本文讲述FFmpeg源码中是怎样解码FLV header,拿到里面的信息。执行命令ffmpeg -i XXX.flv时,FFmpeg源码内部会调用flv_probe函数检测该文件是否为FLV格式的文件(具体可以参考:《音视频入门基础:FLV专题(5)——FFmpeg源码中,判断某文件是否为FLV文件的实现》)。然后如果检测出该文件为FLV格式的文件,会调用flv_read_header函数解码FLV header。

二、flv_read_header函数的定义

flv_read_header函数定义在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的源文件libavformat/flvdec.c中:

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);flags = avio_r8(s->pb);flv->missing_streams = flags & (FLV_HEADER_FLAG_HASVIDEO | FLV_HEADER_FLAG_HASAUDIO);s->ctx_flags |= AVFMTCTX_NOHEADER;offset = avio_rb32(s->pb);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);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;
}

Fmpeg对媒体文件/流进行解复用时,会调用avformat_open_input函数,通过avformat_open_input函数内部的av_probe_input_format3函数来检测该文件是否为FLV格式的文件。如果是,avformat_open_input底层会调用flv_read_header函数来解码FLV header。

所以flv_read_header函数的作用就是解码FLV header。

形参s:既是输入型参数也是输出型参数,指向一个AVFormatContext类型变量。执行flv_read_header函数后,s->priv_data会得到从FLV header中解码出来的信息。然后在flv_read_header函数外部可以通过语句FLVContext *flv = s->priv_data得到这些信息。FLVContext 结构体声明在libavformat/flvdec.c中:

typedef struct FLVContext {const AVClass *class; ///< Class for private options.int trust_metadata;   ///< configure streams according onMetaDataint trust_datasize;   ///< trust data size of FLVTagint dump_full_metadata;   ///< Dump full metadata of the onMetadataint wrong_dts;        ///< wrong dts due to negative ctsuint8_t *new_extradata[FLV_STREAM_TYPE_NB];int new_extradata_size[FLV_STREAM_TYPE_NB];int last_sample_rate;int last_channels;struct {int64_t dts;int64_t pos;} validate_index[2];int validate_next;int validate_count;int searched_for_end;uint8_t resync_buffer[2*RESYNC_BUFFER_SIZE];int broken_sizes;int64_t sum_flv_tag_size;int last_keyframe_stream_index;int keyframe_count;int64_t video_bit_rate;int64_t audio_bit_rate;int64_t *keyframe_times;int64_t *keyframe_filepositions;int missing_streams;AVRational framerate;int64_t last_ts;int64_t time_offset;int64_t time_pos;FLVMetaVideoColor *metaVideoColor;int meta_color_info_flag;
} FLVContext;

返回值:flv_read_header函数固定返回0。

三、flv_read_header函数的内部实现分析

flv_read_header函数中,首先判断该文件是否为KUX文件。kux格式是优酷的一种视频加密格式,为保护版权和经营策略,只能使用优酷播放器播放:

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

AVIOContext文件位置指针(s->pb->buf_ptr)一开始指向FLV header的开头,通过avio_skip函数跳过4个字节,让AVIOContext文件位置指针指向FLV header的第5个字节。关于avio_skip函数用法可以参考:《FFmpeg源码:avio_skip函数分析》:

    avio_skip(s->pb, 4);

读取FLV header的第5个字节,赋值给局部变量flags。从《音视频入门基础:FLV专题(3)——FLV header简介》可以知道,

如果FLV header第5个字节的值为0x04(二进制的0b00000100)表示该FLV文件中仅含有音频不含视频;第5个字节的值为0x01(二进制的0b00000001)表示该FLV文件中仅含有视频不含音频;第5个字节的值为0x05(二进制的0b00000101)表示该FLV文件中既含视频也含音频:

    flags = avio_r8(s->pb);

枚举FLV_HEADER_FLAG_HASVIDEO和FLV_HEADER_FLAG_HASAUDIO声明在libavformat/flv.h中:

enum {FLV_HEADER_FLAG_HASVIDEO = 1,FLV_HEADER_FLAG_HASAUDIO = 4,
};

所以flv->missing_streams = flags & (FLV_HEADER_FLAG_HASVIDEO | FLV_HEADER_FLAG_HASAUDIO)

= flags & (1 | 4)

= flags & 5

所以当flv->missing_streams值为0x04表示该FLV文件中仅含有音频不含视频;flv->missing_streams的值为0x01表示该FLV文件中仅含有视频不含音频;flv->missing_streams的值为0x05表示该FLV文件中既含视频也含音频:

flv->missing_streams = flags & (FLV_HEADER_FLAG_HASVIDEO | FLV_HEADER_FLAG_HASAUDIO);

读取FLV header的第6到第9个字节,即以字节为单位的整个FLV header的长度,赋值给局部变量offset。关于avio_rb32函数用法可以参考:《FFmpeg源码:avio_r8、avio_rl16、avio_rl24、avio_rl32、avio_rl64函数分析》:

    offset = avio_rb32(s->pb);

把AVIOContext的文件位置指针移动到离文件开头offset字节处,即让文件位置指针指向FLV header紧接着的那个字节,也就是PreviousTagSize0。关于avio_seek函数用法可以参考:《FFmpeg源码:avio_seek函数分析》:

    avio_seek(s->pb, offset, SEEK_SET);

 读取FLV文件的PreviousTagSize0,赋值给局部变量pre_tag_size。从《音视频入门基础:FLV专题(3)——FLV header简介》可以知道,PreviousTagSize0,占4个字节,值必须为0。所以如果读取到的PreviousTagSize0值不为0,表示格式错误,打印日志:“Read FLV header error, input file is not a standard flv format, first PreviousTagSize0 always is 0”:

    pre_tag_size = avio_rb32(s->pb);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,flv->sum_flv_tag_size,flv->last_keyframe_stream_index:

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

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com