[FFmpeg-devel] [PATCH 1/3] avformat/mxfenc: H.264 Intra support

Robert Krüger krueger at lesspain.de
Sun Sep 14 17:40:35 CEST 2014


On Sat, Sep 13, 2014 at 12:36 PM, Michael Niedermayer <michaelni at gmx.at> wrote:
> From: Baptiste Coudurier <baptiste.coudurier at gmail.com>
>
> Ported by michael from ffmbc to ffmpeg
> the code is under CONFIG_GPL as ffmbc is GPL
>
> Signed-off-by: Michael Niedermayer <michaelni at gmx.at>
> ---
>  libavformat/mxfenc.c |  143 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 143 insertions(+)
>
> diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
> index 6a6b7c2..98f3479 100644
> --- a/libavformat/mxfenc.c
> +++ b/libavformat/mxfenc.c
> @@ -40,6 +40,8 @@
>  #include "libavutil/avassert.h"
>  #include "libavcodec/bytestream.h"
>  #include "libavcodec/dnxhddata.h"
> +#include "libavcodec/h264.h"
> +#include "libavcodec/internal.h"
>  #include "audiointerleave.h"
>  #include "avformat.h"
>  #include "avio_internal.h"
> @@ -95,6 +97,9 @@ static const struct {
>      { AV_CODEC_ID_PCM_S16LE,  1 },
>      { AV_CODEC_ID_DVVIDEO,   15 },
>      { AV_CODEC_ID_DNXHD,     24 },
> +#if CONFIG_GPL
> +    { AV_CODEC_ID_H264,      34 },
> +#endif
>      { AV_CODEC_ID_NONE }
>  };
>
> @@ -266,6 +271,13 @@ static const MXFContainerEssenceEntry mxf_essence_container_uls[] = {
>        { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
>        { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x13,0x00,0x00 },
>        mxf_write_cdci_desc },
> +#if CONFIG_GPL
> +    // H.264
> +    { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x10,0x60,0x01 },
> +      { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
> +      { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x00,0x00,0x00 },
> +      mxf_write_mpegvideo_desc },
> +#endif // CONFIG_GPL
>      { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
>        { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
>        { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
> @@ -1564,6 +1576,130 @@ static int mxf_parse_dv_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt)
>      return 1;
>  }
>
> +#if CONFIG_GPL
> +static const UID mxf_h264_codec_uls[] = {
> +    { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x30,0x00,0x00 }, // AVC Video
> +    { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x32,0x00,0x00 }, // AVC Intra
> +    { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x32,0x20,0x00 }, // AVC High 10 Intra
> +    { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x01 }, // AVC High 10 Intra RP2027 Class 50 1080/59.94i
> +    { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x02 }, // AVC High 10 Intra RP2027 Class 50 1080/50i
> +    { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x03 }, // AVC High 10 Intra RP2027 Class 50 1080/29.97p
> +    { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x04 }, // AVC High 10 Intra RP2027 Class 50 1080/25p
> +    { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x08 }, // AVC High 10 Intra RP2027 Class 50 720/59.94p
> +    { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x09 }, // AVC High 10 Intra RP2027 Class 50 720/50p
> +    { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x32,0x30,0x00 }, // AVC High 422 Intra
> +    { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x01 }, // AVC High 422 Intra RP2027 Class 100 1080/59.94i
> +    { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x02 }, // AVC High 422 Intra RP2027 Class 100 1080/50i
> +    { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x03 }, // AVC High 422 Intra RP2027 Class 100 1080/29.97p
> +    { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x04 }, // AVC High 422 Intra RP2027 Class 100 1080/25p
> +    { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x08 }, // AVC High 422 Intra RP2027 Class 100 720/59.94p
> +    { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x09 }, // AVC High 422 Intra RP2027 Class 100 720/50p
> +};
> +
> +static const UID *mxf_get_h264_codec_ul(AVCodecContext *avctx, SPS *sps)
> +{
> +    int long_gop = avctx->gop_size > 1 || avctx->has_b_frames;
> +
> +    if ((sps->constraint_set_flags >> 3) & 1) {
> +        if (sps->profile_idc == 110)
> +            return &mxf_h264_codec_uls[2];
> +        else if (sps->profile_idc == 122)
> +            return &mxf_h264_codec_uls[9];
> +    }
> +    if (long_gop)
> +        return &mxf_h264_codec_uls[0];
> +    else
> +        return &mxf_h264_codec_uls[1];
> +}
> +
> +static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st,
> +                                AVPacket *pkt, MXFIndexEntry *e)
> +{
> +    MXFStreamContext *sc = st->priv_data;
> +    H264Context h;
> +    const uint8_t *buf = pkt->data;
> +    const uint8_t *buf_end = pkt->data + pkt->size;
> +    uint32_t state = -1;
> +    AVRational sar = {1, 1};
> +
> +    if (pkt->size < 5 || AV_RB32(pkt->data) != 0x0000001) {
> +        av_log(s, AV_LOG_ERROR, "h264 bitstream malformated, "
> +               "no startcode found, use -vbsf h264_mp4toannexb\n");
> +        return 0;
> +    }
> +
> +    memset(&h, 0, sizeof(h));
> +    h.avctx = st->codec;
> +    h.thread_context[0] = &h;
> +    h.prev_frame_num = -1;
> +
> +    for (;;) {
> +        int src_length, dst_length, consumed;
> +        const uint8_t *ptr;
> +
> +        buf = avpriv_find_start_code(buf, buf_end, &state);
> +        if (buf >= buf_end)
> +            break;
> +        --buf;
> +        src_length = buf_end - buf;
> +        switch (state & 0x1f) {
> +        case NAL_SLICE:
> +        case NAL_IDR_SLICE:
> +            // Do not walk the whole buffer just to decode slice header
> +            if (src_length > 20)
> +                src_length = 20;
> +            break;
> +        }
> +
> +        ptr = ff_h264_decode_nal(&h, buf, &dst_length, &consumed, src_length);
> +        if (!ptr || dst_length < 0)
> +            break;
> +
> +        init_get_bits(&h.gb, ptr, 8*dst_length);
> +        //av_log(avctx, AV_LOG_DEBUG, "nal_unit_type:%d\n", h.nal_unit_type);
> +        switch (h.nal_unit_type) {
> +        case NAL_SPS:
> +            ff_h264_decode_seq_parameter_set(&h);
> +            if (h.sps.sar.num > 0 && h.sps.sar.den > 0) {
> +                sar.num = st->codec->width * h.sps.sar.num;
> +                sar.den = st->codec->height * h.sps.sar.den;
> +            }
> +            sc->aspect_ratio.num = st->codec->width * sar.num;
> +            sc->aspect_ratio.den = st->codec->height * sar.den;
> +            av_reduce(&sc->aspect_ratio.num, &sc->aspect_ratio.den,
> +                      sar.num, sar.den, 1024*1024);
> +
> +            sc->interlaced = !h.sps.frame_mbs_only_flag;
> +            sc->component_depth = h.sps.bit_depth_luma;
> +
> +            sc->codec_ul = mxf_get_h264_codec_ul(st->codec, &h.sps);
> +            e->flags |= 0x40;
> +            break;
> +        case NAL_PPS:
> +            ff_h264_decode_picture_parameter_set(&h, h.gb.size_in_bits);
> +            if (h.sps.timing_info_present_flag) {
> +                if (st->codec->time_base.num != h.sps.num_units_in_tick ||
> +                    st->codec->time_base.den*2 != h.sps.time_scale) {
> +                    av_log(s, AV_LOG_ERROR, "framerate does not match bitstream values: %d/%d != %d/%d\n",
> +                           h.sps.num_units_in_tick, h.sps.time_scale, st->codec->time_base.num, st->codec->time_base.den*2);
> +                    return 0;
> +                }
> +            }
> +            if (e->flags & 0x40) // sequence header present
> +                e->flags |= 0x80; // random access
> +            break;
> +        case NAL_IDR_SLICE:
> +            break;
> +        case NAL_SLICE:
> +            av_log(s, AV_LOG_ERROR, "mxf muxer only supports AVC Intra currently\n");
> +            return 0;
> +        }
> +    }
> +
> +    return !!sc->codec_ul;
> +}
> +#endif // CONFIG_GPL
> +
>  static const UID mxf_mpeg2_codec_uls[] = {
>      { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x01,0x10,0x00 }, // MP-ML I-Frame
>      { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x01,0x11,0x00 }, // MP-ML Long GOP
> @@ -1969,6 +2105,13 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt)
>              av_log(s, AV_LOG_ERROR, "could not get dv profile\n");
>              return -1;
>          }
> +#if CONFIG_GPL
> +    } else if (st->codec->codec_id == AV_CODEC_ID_H264) {
> +        if (!mxf_parse_h264_frame(s, st, pkt, &ie)) {
> +            av_log(s, AV_LOG_ERROR, "could not get h264 profile and level\n");
> +            return -1;
> +        }
> +#endif // CONFIG_GPL
>      }
>
>      if (!mxf->header_written) {
> --
> 1.7.9.5
>

Just a general policy-question: will changes like this not in a way
discourage development of these features in ffmpeg under LGPL? If
someone now uses this code (e.g. mxf_parse_h264_frame) in other code
they will have to make that GPL as well. In the long run this will
make life harder for library users who cannot live with GPL. So far
this hasn't been done on that level, at least not in the part of code
that I am watching. AFAIR currently license borders are normally on a
component level, i.e. a certain codec, format, filter only works only
under GPL, not parts of functionality of a cocec, filter or muxer,
which I think makes it OK to track by people for whom license matters.
this extends this to a level where one would have to know which
features of a certain muxer, codec, filter works under which license.
Of course that's a project maintainer decision. Just wanted to throw
in that side of the story, so it can be consciously taken into account
or disregarded.


More information about the ffmpeg-devel mailing list