On 4/9/2019 7:14 PM, Baptiste Coudurier wrote: > --- > libavformat/Makefile | 2 +- > libavformat/avc.c | 32 +++++++ > libavformat/avc.h | 2 + > libavformat/hevc.c | 36 +------- > libavformat/mxf.h | 1 + > libavformat/mxfenc.c | 201 +++++++++++++++++++++++++++++++++---------- > 6 files changed, 193 insertions(+), 81 deletions(-) > > diff --git a/libavformat/Makefile b/libavformat/Makefile > index c010fc83f9..f8539527bc 100644 > --- a/libavformat/Makefile > +++ b/libavformat/Makefile > @@ -338,7 +338,7 @@ OBJS-$(CONFIG_MUSX_DEMUXER) += musx.o > OBJS-$(CONFIG_MV_DEMUXER) += mvdec.o > OBJS-$(CONFIG_MVI_DEMUXER) += mvi.o > OBJS-$(CONFIG_MXF_DEMUXER) += mxfdec.o mxf.o > -OBJS-$(CONFIG_MXF_MUXER) += mxfenc.o mxf.o audiointerleave.o > +OBJS-$(CONFIG_MXF_MUXER) += mxfenc.o mxf.o audiointerleave.o > avc.o > OBJS-$(CONFIG_MXG_DEMUXER) += mxg.o > OBJS-$(CONFIG_NC_DEMUXER) += ncdec.o > OBJS-$(CONFIG_NISTSPHERE_DEMUXER) += nistspheredec.o pcm.o > diff --git a/libavformat/avc.c b/libavformat/avc.c > index ec50033a04..6c97ae04ab 100644 > --- a/libavformat/avc.c > +++ b/libavformat/avc.c > @@ -241,3 +241,35 @@ const uint8_t *ff_avc_mp4_find_startcode(const uint8_t > *start, > > return start + res; > } > + > +uint8_t *ff_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len, > + uint32_t *dst_len, int header_len)
Nit: Might be a good chance to make src_len and dst_len size_t. > +{ > + uint8_t *dst; > + uint32_t i, len; > + > + dst = av_malloc(src_len + AV_INPUT_BUFFER_PADDING_SIZE); > + if (!dst) > + return NULL; > + > + /* NAL unit header */ > + i = len = 0; > + while (i < header_len && i < src_len) > + dst[len++] = src[i++]; > + > + while (i + 2 < src_len) > + if (!src[i] && !src[i + 1] && src[i + 2] == 3) { > + dst[len++] = src[i++]; > + dst[len++] = src[i++]; > + i++; // remove emulation_prevention_three_byte > + } else > + dst[len++] = src[i++]; > + > + while (i < src_len) > + dst[len++] = src[i++]; > + > + memset(dst + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); > + > + *dst_len = len; > + return dst; > +} [...] > @@ -2168,37 +2227,81 @@ static int mxf_parse_h264_frame(AVFormatContext *s, > AVStream *st, > { > MXFContext *mxf = s->priv_data; > MXFStreamContext *sc = st->priv_data; > - AVCodecParameters *par = st->codecpar; > - static const int mxf_h264_num_codec_uls = sizeof(mxf_h264_codec_uls) / > sizeof(mxf_h264_codec_uls[0]); > + H264ParamSets ps = { { 0 } }; > + GetBitContext gb; > const uint8_t *buf = pkt->data; > const uint8_t *buf_end = pkt->data + pkt->size; > + const uint8_t *tmp, *nal_end; > uint32_t state = -1; > - int long_gop = 0; // assume intra when there is no SPS header > int extra_size = 512; // support AVC Intra files without SPS/PPS header > - int i, frame_size; > - uint8_t uid_found; > - > - if (pkt->size > extra_size) > - buf_end -= pkt->size - extra_size; // no need to parse beyond > SPS/PPS header > + int i, j, tmp_size, frame_size, ret, slice_type, intra_only = 0; > > for (;;) { > buf = avpriv_find_start_code(buf, buf_end, &state); > if (buf >= buf_end) > break; > - --buf; > + > switch (state & 0x1f) { > case H264_NAL_SPS: > - par->profile = buf[1]; > - long_gop = buf[2] & 0x10 ? 0 : 1; // constraint_set3_flag > signals intra > e->flags |= 0x40; > - break; > + > + if (ps.sps != NULL) > + break; > + > + nal_end = ff_avc_find_startcode(buf, buf_end); > + tmp = ff_nal_unit_extract_rbsp(buf, nal_end - buf, &tmp_size, 0); > + if (!buf) { > + av_log(s, AV_LOG_ERROR, "error extracting rbsp\n"); > + return 0; > + } > + init_get_bits(&gb, tmp, tmp_size*8); > + ret = avpriv_h264_decode_seq_parameter_set(&gb, > (AVCodecContext*)s, &ps, 0); > + av_freep(&tmp); > + if (ret < 0) > + return 0; > + for (j = 0; j < MAX_SPS_COUNT; j++) { > + if (ps.sps_list[j] != NULL) { > + ps.sps = (SPS*)ps.sps_list[j]->data; > + break; > + } > + } > + > + sc->aspect_ratio.num = st->codecpar->width * ps.sps->sar.num; > + sc->aspect_ratio.den = st->codecpar->height * ps.sps->sar.den; > + av_reduce(&sc->aspect_ratio.num, &sc->aspect_ratio.den, > + sc->aspect_ratio.num, sc->aspect_ratio.den, 1024*1024); > + intra_only = (ps.sps->constraint_set_flags >> 3) & 1; > + sc->interlaced = !ps.sps->frame_mbs_only_flag; > + sc->component_depth = ps.sps->bit_depth_luma; > + > + buf = nal_end; > + continue; > case H264_NAL_PPS: > if (e->flags & 0x40) { // sequence header present > e->flags |= 0x80; // random access > extra_size = 0; > - buf = buf_end; > } > break; > + case H264_NAL_IDR_SLICE: > + e->flags |= 0x04; // IDR Picture > + buf = buf_end; > + break; > + case H264_NAL_SLICE: > + init_get_bits(&gb, buf, buf_end - buf); > + get_ue_golomb_long(&gb); // skip first_mb_in_slice > + slice_type = get_ue_golomb_31(&gb); > + switch (slice_type % 5) { > + case 0: > + e->flags |= 0x20; // P Picture > + e->flags |= 0x06; // P Picture > + break; > + case 1: > + e->flags |= 0x30; // B Picture > + e->flags |= 0x03; // non-referenced B Picture > + break; > + } > + buf = buf_end; > + break; > default: > break; > } > @@ -2207,27 +2310,35 @@ static int mxf_parse_h264_frame(AVFormatContext *s, > AVStream *st, > if (mxf->header_written) > return 1; > > - sc->aspect_ratio = (AVRational){ 16, 9 }; // 16:9 is mandatory for > broadcast HD > - sc->interlaced = par->field_order != AV_FIELD_PROGRESSIVE ? 1 : 0; > - > - uid_found = 0; > + if (!ps.sps) > + sc->interlaced = st->codecpar->field_order != AV_FIELD_PROGRESSIVE ? > 1 : 0; > + sc->codec_ul = NULL; > frame_size = pkt->size + extra_size; > - for (i = 0; i < mxf_h264_num_codec_uls; i++) { > + > + for (i = 0; i < FF_ARRAY_ELEMS(mxf_h264_codec_uls); i++) { > if (frame_size == mxf_h264_codec_uls[i].frame_size && sc->interlaced > == mxf_h264_codec_uls[i].interlaced) { > sc->codec_ul = &mxf_h264_codec_uls[i].uid; > sc->component_depth = 10; // AVC Intra is always 10 Bit > + sc->aspect_ratio = (AVRational){ 16, 9 }; // 16:9 is mandatory > for broadcast HD > + st->codecpar->profile = mxf_h264_codec_uls[i].profile; > + sc->avc_intra = 1; > if (sc->interlaced) > sc->field_dominance = 1; // top field first is mandatory for > AVC Intra > + mxf->cbr_index = 1; > + sc->frame_size = frame_size; > return 1; > - } else if ((mxf_h264_codec_uls[i].profile == par->profile) && > - ((mxf_h264_codec_uls[i].long_gop < 0) || > - (mxf_h264_codec_uls[i].long_gop == long_gop))) { > + } else if (ps.sps && mxf_h264_codec_uls[i].frame_size == 0 && > + mxf_h264_codec_uls[i].profile == ps.sps->profile_idc && > + (mxf_h264_codec_uls[i].intra_only < 0 || > + mxf_h264_codec_uls[i].intra_only == intra_only)) { > sc->codec_ul = &mxf_h264_codec_uls[i].uid; > - uid_found = 1; > + st->codecpar->profile = ps.sps->profile_idc; > + st->codecpar->level = ps.sps->level_idc; > + // continue to check for avc intra > } > } > > - if (!uid_found) { > + if (!sc->codec_ul) { > av_log(s, AV_LOG_ERROR, "h264 profile not supported\n"); > return 0; > } Ok so, the only fields you need from the sps are constraint_set_flags, frame_mbs_only_flag, bit_depth_luma, profile_idc, level_idc and sar, meaning you don't even need to parse the sps until the very end (sar is the furthest value, and right at the beginning of vui_parameters). I'd very much prefer if we can avoid making ff_h264_decode_seq_parameter_set() avpriv and with it H264ParamSets part of the ABI, so i think it's worth copying the required bitstream parsing code at least until the beginning of vui_parameters. It was done for hevc and av1, so it can be done for h264 as well. If you look a the h264 module from the CBS framework (cbs_h264) in libavcodec, you'll find a very simple parsing implementation that doesn't bother to decode the values, or fill tables, or allocate any kind of buffer like the h264_ps.c does. You in fact will not need to even store any value beyond the ones i listed above. Writing a reusable and expansible-as-needed sps parsing function in libavformat shouldn't be hard with the above module, and would be much cleaner and less constraining in the long run for both libavformat and libavcodec. _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".