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".

Reply via email to