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
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".