标签:main locate error out rgba ref number rational ffmpeg
解析器主要就是解析出NALU,以及解析一些SPS、PPS等信息,下面分析一下ff_h264_parser
AVCodecParser ff_h264_parser = { .codec_ids = { AV_CODEC_ID_H264 }, .priv_data_size = sizeof(H264ParseContext), .parser_init = init, .parser_parse = h264_parse, .parser_close = h264_close, .split = h264_split, };
static av_cold int init(AVCodecParserContext *s) { H264ParseContext *p = s->priv_data; p->reference_dts = AV_NOPTS_VALUE; p->last_frame_num = INT_MAX; ff_h264dsp_init(&p->h264dsp, 8, 1); return 0; }
初始化比较简单,就是一些基本的参数设置
h264_close()
static void h264_close(AVCodecParserContext *s) { H264ParseContext *p = s->priv_data; ParseContext *pc = &p->pc; av_freep(&pc->buffer); ff_h264_sei_uninit(&p->sei); ff_h264_ps_uninit(&p->ps); }
结束这里就是释放AVCodecParserContext对象
h264_parse()
static int h264_parse(AVCodecParserContext *s, AVCodecContext *avctx, const uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size) { H264ParseContext *p = s->priv_data; ParseContext *pc = &p->pc; int next; // 获取extradata,一般保存SPS、PPS等信息 if (!p->got_first) { p->got_first = 1; if (avctx->extradata_size) { ff_h264_decode_extradata(avctx->extradata, avctx->extradata_size, &p->ps, &p->is_avc, &p->nal_length_size, avctx->err_recognition, avctx); } } if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { next = buf_size; } else { // 查找帧结尾位置,以起始码(0x000001或0x00000001)为依据 // SPS和PPS会被一起找到,第一个数据尾:SPS+PPS next = h264_find_frame_end(p, buf, buf_size, avctx); // next < 0 : 非一帧,数据缓存到pc->buffer // next >=0 : 找到一帧,将数据和之前缓存的数据打包一帧到buf if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { *poutbuf = NULL; *poutbuf_size = 0; return buf_size; } if (next < 0 && next != END_NOT_FOUND) { av_assert1(pc->last_index + next >= 0); h264_find_frame_end(p, &pc->buffer[pc->last_index + next], -next, avctx); // update state } } // 解析NALU,从SPS和PPS等中获取一些信息 parse_nal_units(s, avctx, buf, buf_size); if (avctx->framerate.num) avctx->time_base = av_inv_q(av_mul_q(avctx->framerate, (AVRational){avctx->ticks_per_frame, 1})); if (p->sei.picture_timing.cpb_removal_delay >= 0) { s->dts_sync_point = p->sei.buffering_period.present; s->dts_ref_dts_delta = p->sei.picture_timing.cpb_removal_delay; s->pts_dts_delta = p->sei.picture_timing.dpb_output_delay; } else { s->dts_sync_point = INT_MIN; s->dts_ref_dts_delta = INT_MIN; s->pts_dts_delta = INT_MIN; } if (s->flags & PARSER_FLAG_ONCE) { s->flags &= PARSER_FLAG_COMPLETE_FRAMES; } if (s->dts_sync_point >= 0) { int64_t den = avctx->time_base.den * (int64_t)avctx->pkt_timebase.num; if (den > 0) { int64_t num = avctx->time_base.num * (int64_t)avctx->pkt_timebase.den; if (s->dts != AV_NOPTS_VALUE) { // got DTS from the stream, update reference timestamp p->reference_dts = s->dts - av_rescale(s->dts_ref_dts_delta, num, den); } else if (p->reference_dts != AV_NOPTS_VALUE) { // compute DTS based on reference timestamp s->dts = p->reference_dts + av_rescale(s->dts_ref_dts_delta, num, den); } if (p->reference_dts != AV_NOPTS_VALUE && s->pts == AV_NOPTS_VALUE) s->pts = s->dts + av_rescale(s->pts_dts_delta, num, den); if (s->dts_sync_point > 0) p->reference_dts = s->dts; // new reference } } // 将完整的一帧输出到poutbuf *poutbuf = buf; *poutbuf_size = buf_size; return next; }
这里主要做了几件事:
int ff_h264_decode_extradata(const uint8_t *data, int size, H264ParamSets *ps, int *is_avc, int *nal_length_size, int err_recognition, void *logctx) { int ret; if (!data || size <= 0) return -1; if (data[0] == 1) { int i, cnt, nalsize; const uint8_t *p = data; *is_avc = 1; if (size < 7) { av_log(logctx, AV_LOG_ERROR, "avcC %d too short\n", size); return AVERROR_INVALIDDATA; } // Decode sps from avcC // 解码SPS cnt = *(p + 5) & 0x1f; // Number of sps p += 6; for (i = 0; i < cnt; i++) { nalsize = AV_RB16(p) + 2; if (nalsize > size - (p - data)) return AVERROR_INVALIDDATA; ret = decode_extradata_ps_mp4(p, nalsize, ps, err_recognition, logctx); if (ret < 0) { av_log(logctx, AV_LOG_ERROR, "Decoding sps %d from avcC failed\n", i); return ret; } p += nalsize; } // Decode pps from avcC // 解码PPS cnt = *(p++); // Number of pps for (i = 0; i < cnt; i++) { nalsize = AV_RB16(p) + 2; if (nalsize > size - (p - data)) return AVERROR_INVALIDDATA; ret = decode_extradata_ps_mp4(p, nalsize, ps, err_recognition, logctx); if (ret < 0) { av_log(logctx, AV_LOG_ERROR, "Decoding pps %d from avcC failed\n", i); return ret; } p += nalsize; } // Store right nal length size that will be used to parse all other nals *nal_length_size = (data[4] & 0x03) + 1; } else { *is_avc = 0; ret = decode_extradata_ps(data, size, ps, 0, logctx); if (ret < 0) return ret; } return size; }
这里extradata存储的其实是SPS和PPS,解析可以获取SPS和PPS,像FLV这些格式SPS和PPS是存储在extradata里的
static int h264_find_frame_end(H264ParseContext *p, const uint8_t *buf, int buf_size, void *logctx) { int i, j; uint32_t state; ParseContext *pc = &p->pc; int next_avc = p->is_avc ? 0 : buf_size; // mb_addr= pc->mb_addr - 1; state = pc->state; if (state > 13) state = 7; if (p->is_avc && !p->nal_length_size) av_log(logctx, AV_LOG_ERROR, "AVC-parser: nal length size invalid\n"); for (i = 0; i < buf_size; i++) { if (i >= next_avc) { int nalsize = 0; i = next_avc; for (j = 0; j < p->nal_length_size; j++) nalsize = (nalsize << 8) | buf[i++]; if (nalsize <= 0 || nalsize > buf_size - i) { av_log(logctx, AV_LOG_ERROR, "AVC-parser: nal size %d remaining %d\n", nalsize, buf_size - i); return buf_size; } next_avc = i + nalsize; state = 5; } // 这里有个状态机,通过状态机查找start_code来找一帧 // 7 - 初始化状态 // 2 - 找到1个0 // 1 - 找到2个0 // 0 - 找到大于等于3个0 // 4 - 找到2个0和1个1,即001(即找到了起始码) // 5 - 找到至少3个0和1个1,即0001等等(即找到了起始码) // >=8 - 找到2个Slice Header if (state == 7) { // 查找0的位置 i += p->h264dsp.startcode_find_candidate(buf + i, next_avc - i); if (i < next_avc) state = 2; } else if (state <= 2) { if (buf[i] == 1) state ^= 5; // 2->7, 1->4, 0->5 else if (buf[i]) state = 7; else state >>= 1; // 2->1, 1->0, 0->0 } else if (state <= 5) { int nalu_type = buf[i] & 0x1F; if (nalu_type == H264_NAL_SEI || nalu_type == H264_NAL_SPS || nalu_type == H264_NAL_PPS || nalu_type == H264_NAL_AUD) { if (pc->frame_start_found) { i++; goto found; } } else if (nalu_type == H264_NAL_SLICE || nalu_type == H264_NAL_DPA || nalu_type == H264_NAL_IDR_SLICE) { state += 8; continue; } state = 7; } else { unsigned int mb, last_mb = p->parse_last_mb; GetBitContext gb; p->parse_history[p->parse_history_count++] = buf[i]; init_get_bits(&gb, p->parse_history, 8*p->parse_history_count); mb= get_ue_golomb_long(&gb); if (get_bits_left(&gb) > 0 || p->parse_history_count > 5) { p->parse_last_mb = mb; if (pc->frame_start_found) { if (mb <= last_mb) { i -= p->parse_history_count - 1; p->parse_history_count = 0; goto found; } } else pc->frame_start_found = 1; p->parse_history_count = 0; state = 7; } } } pc->state = state; if (p->is_avc) return next_avc; return END_NOT_FOUND; found: pc->state = 7; pc->frame_start_found = 0; if (p->is_avc) return next_avc; return i - (state & 5); }
这里主要是通过startcode去查找一帧NALU的位置。
int ff_combine_frame(ParseContext *pc, int next, const uint8_t **buf, int *buf_size) { if (pc->overread) { ff_dlog(NULL, "overread %d, state:%"PRIX32" next:%d index:%d o_index:%d\n", pc->overread, pc->state, next, pc->index, pc->overread_index); ff_dlog(NULL, "%X %X %X %X\n", (*buf)[0], (*buf)[1], (*buf)[2], (*buf)[3]); } /* Copy overread bytes from last frame into buffer. */ for (; pc->overread > 0; pc->overread--) pc->buffer[pc->index++] = pc->buffer[pc->overread_index++]; if (next > *buf_size) return AVERROR(EINVAL); /* flush remaining if EOF */ if (!*buf_size && next == END_NOT_FOUND) next = 0; pc->last_index = pc->index; /* copy into buffer end return */ // 没找到数据缓存到pc->buffer if (next == END_NOT_FOUND) { void *new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size, *buf_size + pc->index + AV_INPUT_BUFFER_PADDING_SIZE); if (!new_buffer) { av_log(NULL, AV_LOG_ERROR, "Failed to reallocate parser buffer to %d\n", *buf_size + pc->index + AV_INPUT_BUFFER_PADDING_SIZE); pc->index = 0; return AVERROR(ENOMEM); } pc->buffer = new_buffer; memcpy(&pc->buffer[pc->index], *buf, *buf_size); pc->index += *buf_size; return -1; } av_assert0(next >= 0 || pc->buffer); *buf_size = pc->overread_index = pc->index + next; /* append to buffer */ // 找到就把数据组装buf里 if (pc->index) { void *new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size, next + pc->index + AV_INPUT_BUFFER_PADDING_SIZE); if (!new_buffer) { av_log(NULL, AV_LOG_ERROR, "Failed to reallocate parser buffer to %d\n", next + pc->index + AV_INPUT_BUFFER_PADDING_SIZE); pc->overread_index = pc->index = 0; return AVERROR(ENOMEM); } pc->buffer = new_buffer; if (next > -AV_INPUT_BUFFER_PADDING_SIZE) memcpy(&pc->buffer[pc->index], *buf, next + AV_INPUT_BUFFER_PADDING_SIZE); pc->index = 0; *buf = pc->buffer; } /* store overread bytes */ for (; next < 0; next++) { pc->state = pc->state << 8 | pc->buffer[pc->last_index + next]; pc->state64 = pc->state64 << 8 | pc->buffer[pc->last_index + next]; pc->overread++; } if (pc->overread) { ff_dlog(NULL, "overread %d, state:%"PRIX32" next:%d index:%d o_index:%d\n", pc->overread, pc->state, next, pc->index, pc->overread_index); ff_dlog(NULL, "%X %X %X %X\n", (*buf)[0], (*buf)[1], (*buf)[2], (*buf)[3]); } return 0; }
这里主要做了两件事:
标签:main locate error out rgba ref number rational ffmpeg
原文地址:https://www.cnblogs.com/vczf/p/14837759.html