概述
/*单位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 0n");
}
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|数组元素名长度|数组元素名(字符串'