[FFmpeg-devel] avformat/mxfenc: support XAVC long gop

Submitted by Baptiste Coudurier on May 10, 2019, 3:50 p.m.

Details

Message ID 20190510155037.87920-1-baptiste.coudurier@gmail.com
State New
Headers show

Commit Message

Baptiste Coudurier May 10, 2019, 3:50 p.m.
---
 libavformat/Makefile |   2 +-
 libavformat/avc.c    | 188 ++++++++++++++++++++++++++++++++++++++
 libavformat/avc.h    |  15 +++
 libavformat/hevc.c   |  36 +-------
 libavformat/mxf.h    |   1 +
 libavformat/mxfenc.c | 213 ++++++++++++++++++++++++++++++++++---------
 6 files changed, 374 insertions(+), 81 deletions(-)

Comments

Tomas Härdin May 12, 2019, 1:47 p.m.
fre 2019-05-10 klockan 08:50 -0700 skrev Baptiste Coudurier:
> +static inline int get_ue_golomb(GetBitContext *gb) {
> +    int i, v;
> +    for (i = 0; i < 32 && !get_bits1(gb); i++)
> +        ;
> +    for (v = 1; i--;)
> +        v = (v << 1) | get_bits1(gb);

Isn't there already a function to get variable number of bits?

> +    return v - 1;
> +}

> +
> +static inline int get_se_golomb(GetBitContext *gb) {
> +    int v = get_ue_golomb(gb) + 1;
> +    int sign = -(v & 1);
> +    return ((v >> 1) ^ sign) - sign;
> +}
> +
> +H264SequenceParameterSet *ff_avc_decode_sps(const uint8_t *buf, int buf_size)
> +{
> +    int i, j, ret, rbsp_size, aspect_ratio_idc, pic_order_cnt_type;
> +    int num_ref_frames_in_pic_order_cnt_cycle;
> +    int delta_scale, lastScale = 8, nextScale = 8;
> +    int sizeOfScalingList;
> +    H264SequenceParameterSet *sps = NULL;
> +    GetBitContext gb;
> +    uint8_t *rbsp_buf;
> +
> +    rbsp_buf = ff_nal_unit_extract_rbsp(buf, buf_size, &rbsp_size, 0);
> +    if (!rbsp_buf)
> +        return NULL;
> +
> +    ret = init_get_bits8(&gb, rbsp_buf, rbsp_size);
> +    if (ret < 0)
> +        goto end;
> +
> +    sps = av_mallocz(sizeof(*sps));
> +    if (!sps)
> +        goto end;
> +
> +    sps->profile_idc = get_bits(&gb, 8);
> +    sps->constraint_set_flags |= get_bits1(&gb) << 0; // constraint_set0_flag
> +    sps->constraint_set_flags |= get_bits1(&gb) << 1; // constraint_set1_flag
> +    sps->constraint_set_flags |= get_bits1(&gb) << 2; // constraint_set2_flag
> +    sps->constraint_set_flags |= get_bits1(&gb) << 3; // constraint_set3_flag
> +    sps->constraint_set_flags |= get_bits1(&gb) << 4; // constraint_set4_flag
> +    sps->constraint_set_flags |= get_bits1(&gb) << 5; // constraint_set5_flag

Why not just get 6 bits at once?

> +    skip_bits(&gb, 2); // reserved_zero_2bits
> +    sps->level_idc = get_bits(&gb, 8);
> +    sps->id = get_ue_golomb(&gb);
> +
> +    if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
> +        sps->profile_idc == 122 || sps->profile_idc == 244 || sps->profile_idc ==  44 ||
> +        sps->profile_idc ==  83 || sps->profile_idc ==  86 || sps->profile_idc == 118 ||
> +        sps->profile_idc == 128 || sps->profile_idc == 138 || sps->profile_idc == 139 ||
> +        sps->profile_idc == 134) {

Maybe put these in a table instead? I guess it works this way, just a
bit verbose. They could do with sorting, unless there's a specific
reason for this ordering
 
> +static void mxf_write_local_tags(AVIOContext *pb, const MXFLocalTagPair *local_tags, int count)
> +{
> +    int i;
> +    for (i = 0; i < count; i++) {
> +        avio_wb16(pb, local_tags[i].local_tag);
> +        avio_write(pb, local_tags[i].uid, 16);
> +    }
> +}

This function could be used to simplify mxf_write_primer_pack(). But
that probably belongs in a separate patch.

> +
>  static void mxf_write_primer_pack(AVFormatContext *s)
>  {
>      MXFContext *mxf = s->priv_data;
>      AVIOContext *pb = s->pb;
>      int local_tag_number, i = 0;
> +    int avc_tags_count = 0;
>  
>      local_tag_number = FF_ARRAY_ELEMS(mxf_local_tag_batch);
>      local_tag_number += mxf->store_user_comments * FF_ARRAY_ELEMS(mxf_user_comments_local_tag);
>  
> +    for (i = 0; i < s->nb_streams; i++) {
> +        MXFStreamContext *sc = s->streams[i]->priv_data;
> +        if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_H264 && !sc->avc_intra) {
> +            avc_tags_count = FF_ARRAY_ELEMS(mxf_avc_subdescriptor_local_tags);
> +            local_tag_number += avc_tags_count;

This will output a broken file if there's more than one XAVC stream.
Not possible now I think, but will be a problem is someone decides to
give higher operational patterns a try

> +        }
> +    }
> +
>      avio_write(pb, primer_pack_key, 16);
>      klv_encode_ber_length(pb, local_tag_number * 18 + 8);
>  
> @@ -608,6 +637,8 @@ static void mxf_write_primer_pack(AVFormatContext *s)
>              avio_wb16(pb, mxf_user_comments_local_tag[i].local_tag);
>              avio_write(pb, mxf_user_comments_local_tag[i].uid, 16);
>          }
> +    if (avc_tags_count > 0)
> +        mxf_write_local_tags(pb, mxf_avc_subdescriptor_local_tags, avc_tags_count);
>  }

No other comments for now. Don't know enough about SPS/PPS stuff to
comment on specifics about that.

/Tomas
Mark Thompson May 12, 2019, 5:03 p.m.
On 12/05/2019 14:47, Tomas Härdin wrote:
> fre 2019-05-10 klockan 08:50 -0700 skrev Baptiste Coudurier:
>> ...
>> +    skip_bits(&gb, 2); // reserved_zero_2bits
>> +    sps->level_idc = get_bits(&gb, 8);
>> +    sps->id = get_ue_golomb(&gb);
>> +
>> +    if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
>> +        sps->profile_idc == 122 || sps->profile_idc == 244 || sps->profile_idc ==  44 ||
>> +        sps->profile_idc ==  83 || sps->profile_idc ==  86 || sps->profile_idc == 118 ||
>> +        sps->profile_idc == 128 || sps->profile_idc == 138 || sps->profile_idc == 139 ||
>> +        sps->profile_idc == 134) {
> 
> Maybe put these in a table instead? I guess it works this way, just a
> bit verbose. They could do with sorting, unless there's a specific
> reason for this ordering

This is exactly how it appears in the standard (see section 7.3.2.1.1).  IMO it's better to match that exactly than to do something else.

- Mark
Baptiste Coudurier May 12, 2019, 8:02 p.m.
Hi Tomas

> On May 12, 2019, at 6:47 AM, Tomas Härdin <tjoppen@acc.umu.se> wrote:
> 
> fre 2019-05-10 klockan 08:50 -0700 skrev Baptiste Coudurier:
>> +static inline int get_ue_golomb(GetBitContext *gb) {
>> +    int i, v;
>> +    for (i = 0; i < 32 && !get_bits1(gb); i++)
>> +        ;
>> +    for (v = 1; i--;)
>> +        v = (v << 1) | get_bits1(gb);
> 
> Isn't there already a function to get variable number of bits?

get_bits doesn’t work for n == 0

>> 
>> +
>> +    sps->profile_idc = get_bits(&gb, 8);
>> +    sps->constraint_set_flags |= get_bits1(&gb) << 0; // constraint_set0_flag
>> +    sps->constraint_set_flags |= get_bits1(&gb) << 1; // constraint_set1_flag
>> +    sps->constraint_set_flags |= get_bits1(&gb) << 2; // constraint_set2_flag
>> +    sps->constraint_set_flags |= get_bits1(&gb) << 3; // constraint_set3_flag
>> +    sps->constraint_set_flags |= get_bits1(&gb) << 4; // constraint_set4_flag
>> +    sps->constraint_set_flags |= get_bits1(&gb) << 5; // constraint_set5_flag
> 
> Why not just get 6 bits at once?

That’s how it’s done in h264_ps.c currently.
 
>> +static void mxf_write_local_tags(AVIOContext *pb, const MXFLocalTagPair *local_tags, int count)
>> +{
>> +    int i;
>> +    for (i = 0; i < count; i++) {
>> +        avio_wb16(pb, local_tags[i].local_tag);
>> +        avio_write(pb, local_tags[i].uid, 16);
>> +    }
>> +}
> 
> This function could be used to simplify mxf_write_primer_pack(). But
> that probably belongs in a separate patch.

Yes, it does

>> +
>>  static void mxf_write_primer_pack(AVFormatContext *s)
>>  {
>>      MXFContext *mxf = s->priv_data;
>>      AVIOContext *pb = s->pb;
>>      int local_tag_number, i = 0;
>> +    int avc_tags_count = 0;
>>  
>>      local_tag_number = FF_ARRAY_ELEMS(mxf_local_tag_batch);
>>      local_tag_number += mxf->store_user_comments * FF_ARRAY_ELEMS(mxf_user_comments_local_tag);
>>  
>> +    for (i = 0; i < s->nb_streams; i++) {
>> +        MXFStreamContext *sc = s->streams[i]->priv_data;
>> +        if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_H264 && !sc->avc_intra) {
>> +            avc_tags_count = FF_ARRAY_ELEMS(mxf_avc_subdescriptor_local_tags);
>> +            local_tag_number += avc_tags_count;
> 
> This will output a broken file if there's more than one XAVC stream.
> Not possible now I think, but will be a problem is someone decides to
> give higher operational patterns a try

Yes, it will get caught when this happens.

— 
Baptiste
Paul B Mahol May 12, 2019, 8:39 p.m.
On 5/12/19, Baptiste Coudurier <baptiste.coudurier@gmail.com> wrote:
> Hi Tomas
>
>> On May 12, 2019, at 6:47 AM, Tomas Härdin <tjoppen@acc.umu.se> wrote:
>>
>> fre 2019-05-10 klockan 08:50 -0700 skrev Baptiste Coudurier:
>>> +static inline int get_ue_golomb(GetBitContext *gb) {
>>> +    int i, v;
>>> +    for (i = 0; i < 32 && !get_bits1(gb); i++)
>>> +        ;
>>> +    for (v = 1; i--;)
>>> +        v = (v << 1) | get_bits1(gb);
>>
>> Isn't there already a function to get variable number of bits?
>
> get_bits doesn’t work for n == 0

There is get_bitsz. Or I misunderstood?

>
>>>
>>> +
>>> +    sps->profile_idc = get_bits(&gb, 8);
>>> +    sps->constraint_set_flags |= get_bits1(&gb) << 0; //
>>> constraint_set0_flag
>>> +    sps->constraint_set_flags |= get_bits1(&gb) << 1; //
>>> constraint_set1_flag
>>> +    sps->constraint_set_flags |= get_bits1(&gb) << 2; //
>>> constraint_set2_flag
>>> +    sps->constraint_set_flags |= get_bits1(&gb) << 3; //
>>> constraint_set3_flag
>>> +    sps->constraint_set_flags |= get_bits1(&gb) << 4; //
>>> constraint_set4_flag
>>> +    sps->constraint_set_flags |= get_bits1(&gb) << 5; //
>>> constraint_set5_flag
>>
>> Why not just get 6 bits at once?
>
> That’s how it’s done in h264_ps.c currently.
>
>>> +static void mxf_write_local_tags(AVIOContext *pb, const MXFLocalTagPair
>>> *local_tags, int count)
>>> +{
>>> +    int i;
>>> +    for (i = 0; i < count; i++) {
>>> +        avio_wb16(pb, local_tags[i].local_tag);
>>> +        avio_write(pb, local_tags[i].uid, 16);
>>> +    }
>>> +}
>>
>> This function could be used to simplify mxf_write_primer_pack(). But
>> that probably belongs in a separate patch.
>
> Yes, it does
>
>>> +
>>>  static void mxf_write_primer_pack(AVFormatContext *s)
>>>  {
>>>      MXFContext *mxf = s->priv_data;
>>>      AVIOContext *pb = s->pb;
>>>      int local_tag_number, i = 0;
>>> +    int avc_tags_count = 0;
>>>
>>>      local_tag_number = FF_ARRAY_ELEMS(mxf_local_tag_batch);
>>>      local_tag_number += mxf->store_user_comments *
>>> FF_ARRAY_ELEMS(mxf_user_comments_local_tag);
>>>
>>> +    for (i = 0; i < s->nb_streams; i++) {
>>> +        MXFStreamContext *sc = s->streams[i]->priv_data;
>>> +        if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_H264 &&
>>> !sc->avc_intra) {
>>> +            avc_tags_count =
>>> FF_ARRAY_ELEMS(mxf_avc_subdescriptor_local_tags);
>>> +            local_tag_number += avc_tags_count;
>>
>> This will output a broken file if there's more than one XAVC stream.
>> Not possible now I think, but will be a problem is someone decides to
>> give higher operational patterns a try
>
> Yes, it will get caught when this happens.
>
> —
> Baptiste
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Baptiste Coudurier May 13, 2019, 4:59 a.m.
> On May 12, 2019, at 1:39 PM, Paul B Mahol <onemda@gmail.com> wrote:
> 
> On 5/12/19, Baptiste Coudurier <baptiste.coudurier@gmail.com <mailto:baptiste.coudurier@gmail.com>> wrote:
>> Hi Tomas
>> 
>>> On May 12, 2019, at 6:47 AM, Tomas Härdin <tjoppen@acc.umu.se> wrote:
>>> 
>>> fre 2019-05-10 klockan 08:50 -0700 skrev Baptiste Coudurier:
>>>> +static inline int get_ue_golomb(GetBitContext *gb) {
>>>> +    int i, v;
>>>> +    for (i = 0; i < 32 && !get_bits1(gb); i++)
>>>> +        ;
>>>> +    for (v = 1; i--;)
>>>> +        v = (v << 1) | get_bits1(gb);
>>> 
>>> Isn't there already a function to get variable number of bits?
>> 
>> get_bits doesn’t work for n == 0
> 
> There is get_bitsz. Or I misunderstood?

Nice, updated.

— 
Baptiste
Tomas Härdin May 13, 2019, 12:25 p.m.
sön 2019-05-12 klockan 18:03 +0100 skrev Mark Thompson:
> On 12/05/2019 14:47, Tomas Härdin wrote:
> > fre 2019-05-10 klockan 08:50 -0700 skrev Baptiste Coudurier:
> > > ...
> > > +    skip_bits(&gb, 2); // reserved_zero_2bits
> > > +    sps->level_idc = get_bits(&gb, 8);
> > > +    sps->id = get_ue_golomb(&gb);
> > > +
> > > +    if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
> > > +        sps->profile_idc == 122 || sps->profile_idc == 244 || sps->profile_idc ==  44 ||
> > > +        sps->profile_idc ==  83 || sps->profile_idc ==  86 || sps->profile_idc == 118 ||
> > > +        sps->profile_idc == 128 || sps->profile_idc == 138 || sps->profile_idc == 139 ||
> > > +        sps->profile_idc == 134) {
> > 
> > Maybe put these in a table instead? I guess it works this way, just a
> > bit verbose. They could do with sorting, unless there's a specific
> > reason for this ordering
> 
> This is exactly how it appears in the standard (see section
> 7.3.2.1.1).  IMO it's better to match that exactly than to do
> something else.

Fair enough

/Tomas
Thomas Mundt May 13, 2019, 10:11 p.m.
Hi Baptiste,

Am Fr., 10. Mai 2019 um 17:51 Uhr schrieb Baptiste Coudurier <
baptiste.coudurier@gmail.com>:

> ---
>  libavformat/Makefile |   2 +-
>  libavformat/avc.c    | 188 ++++++++++++++++++++++++++++++++++++++
>  libavformat/avc.h    |  15 +++
>  libavformat/hevc.c   |  36 +-------
>  libavformat/mxf.h    |   1 +
>  libavformat/mxfenc.c | 213 ++++++++++++++++++++++++++++++++++---------
>  6 files changed, 374 insertions(+), 81 deletions(-)
> [...]

+static const MXFLocalTagPair mxf_avc_subdescriptor_local_tags[] = {
> +    { 0x8100,
> {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x04,0x06,0x10,0x00,0x00}},
> /* SubDescriptors */
> +    { 0x8200,
> {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x01,0x06,0x06,0x01,0x0E,0x00,0x00}},
> /* AVC Decoding Delay */
> +    { 0x8201,
> {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x01,0x06,0x06,0x01,0x0A,0x00,0x00}},
> /* AVC Profile */
> +    { 0x8202,
> {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x01,0x06,0x06,0x01,0x0D,0x00,0x00}},
> /* AVC Level */
> +};
> +
> [...]
> +static void mxf_write_avc_subdesc(AVFormatContext *s, AVStream *st)
> +{
> +    AVIOContext *pb = s->pb;
> +    int64_t pos;
> +
> +    avio_write(pb, mxf_avc_subdescriptor_key, 16);
> +    klv_encode_ber4_length(pb, 0);
> +    pos = avio_tell(pb);
> +
> +    mxf_write_local_tag(pb, 16, 0x3C0A);
> +    mxf_write_uuid(pb, AVCSubDescriptor, 0);
> +
> +    mxf_write_local_tag(pb, 1, 0x8200);
> +    avio_w8(pb, 0xFF); // AVC Decoding Delay, unknown
> +
> +    mxf_write_local_tag(pb, 1, 0x8201);
> +    avio_w8(pb, st->codecpar->profile); // AVC Profile
> +
> +    mxf_write_local_tag(pb, 1, 0x8202);
> +    avio_w8(pb, st->codecpar->level); // AVC Level
> +
> +    mxf_update_klv_size(s->pb, pos);
> +}
>

Other MXF muxers, e.g. bmxlib, also write the avc profile constraint tag
when the avc subdescriptor is used. At least MediaInfo detects intra coded
files as long gop otherwise.

FFmpeg crashes with this patch when I try to remux AVC Intra files without
SPS/PPS header.
Tested on Windows 7. Compiled with msys2/gcc7.3.0 x86-32bit.
Command: ffmpeg -i AVCI100_Test.mxf -c:v copy out.mxf
Test file:
https://www.mediafire.com/file/n0oi50u39yi3qpr/AVCI100_Test.mxf/file

Regards,
Thomas
Baptiste Coudurier May 13, 2019, 10:33 p.m.
Hi Thomas

> On May 13, 2019, at 3:11 PM, Thomas Mundt <tmundt75@gmail.com> wrote:
> 
> Hi Baptiste,
> 
> Am Fr., 10. Mai 2019 um 17:51 Uhr schrieb Baptiste Coudurier <
> baptiste.coudurier@gmail.com>:
> 
>> ---
>> libavformat/Makefile |   2 +-
>> libavformat/avc.c    | 188 ++++++++++++++++++++++++++++++++++++++
>> libavformat/avc.h    |  15 +++
>> libavformat/hevc.c   |  36 +-------
>> libavformat/mxf.h    |   1 +
>> libavformat/mxfenc.c | 213 ++++++++++++++++++++++++++++++++++---------
>> 6 files changed, 374 insertions(+), 81 deletions(-)
>> [...]
> 
> +static const MXFLocalTagPair mxf_avc_subdescriptor_local_tags[] = {
>> +    { 0x8100,
>> {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x04,0x06,0x10,0x00,0x00}},
>> /* SubDescriptors */
>> +    { 0x8200,
>> {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x01,0x06,0x06,0x01,0x0E,0x00,0x00}},
>> /* AVC Decoding Delay */
>> +    { 0x8201,
>> {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x01,0x06,0x06,0x01,0x0A,0x00,0x00}},
>> /* AVC Profile */
>> +    { 0x8202,
>> {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x01,0x06,0x06,0x01,0x0D,0x00,0x00}},
>> /* AVC Level */
>> +};
>> +
>> [...]
>> +static void mxf_write_avc_subdesc(AVFormatContext *s, AVStream *st)
>> +{
>> +    AVIOContext *pb = s->pb;
>> +    int64_t pos;
>> +
>> +    avio_write(pb, mxf_avc_subdescriptor_key, 16);
>> +    klv_encode_ber4_length(pb, 0);
>> +    pos = avio_tell(pb);
>> +
>> +    mxf_write_local_tag(pb, 16, 0x3C0A);
>> +    mxf_write_uuid(pb, AVCSubDescriptor, 0);
>> +
>> +    mxf_write_local_tag(pb, 1, 0x8200);
>> +    avio_w8(pb, 0xFF); // AVC Decoding Delay, unknown
>> +
>> +    mxf_write_local_tag(pb, 1, 0x8201);
>> +    avio_w8(pb, st->codecpar->profile); // AVC Profile
>> +
>> +    mxf_write_local_tag(pb, 1, 0x8202);
>> +    avio_w8(pb, st->codecpar->level); // AVC Level
>> +
>> +    mxf_update_klv_size(s->pb, pos);
>> +}
>> 
> 
> Other MXF muxers, e.g. bmxlib, also write the avc profile constraint tag
> when the avc subdescriptor is used. At least MediaInfo detects intra coded
> files as long gop otherwise.

I prefer not writing optional values unless actually required by actual decoders.
I think MediaInfo should be fixed in this case, it is obviously wrong.

> FFmpeg crashes with this patch when I try to remux AVC Intra files without
> SPS/PPS header.
> Tested on Windows 7. Compiled with msys2/gcc7.3.0 x86-32bit.
> Command: ffmpeg -i AVCI100_Test.mxf -c:v copy out.mxf
> Test file:
> https://www.mediafire.com/file/n0oi50u39yi3qpr/AVCI100_Test.mxf/file <https://www.mediafire.com/file/n0oi50u39yi3qpr/AVCI100_Test.mxf/file>

Strange, why doesn’t gcc emit a warning for SPS might be initialized in this case…
Fixed in an updated patch.

— 
Baptiste

Patch hide | download patch | download mbox

diff --git a/libavformat/Makefile b/libavformat/Makefile
index 99be60d184..df87c54a58 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -339,7 +339,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..8f53228bf3 100644
--- a/libavformat/avc.c
+++ b/libavformat/avc.c
@@ -21,6 +21,7 @@ 
 
 #include "libavutil/intreadwrite.h"
 #include "libavcodec/h264.h"
+#include "libavcodec/get_bits.h"
 #include "avformat.h"
 #include "avio.h"
 #include "avc.h"
@@ -241,3 +242,190 @@  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)
+{
+    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;
+}
+
+static const AVRational avc_sample_aspect_ratio[17] = {
+    {   0,  1 },
+    {   1,  1 },
+    {  12, 11 },
+    {  10, 11 },
+    {  16, 11 },
+    {  40, 33 },
+    {  24, 11 },
+    {  20, 11 },
+    {  32, 11 },
+    {  80, 33 },
+    {  18, 11 },
+    {  15, 11 },
+    {  64, 33 },
+    { 160, 99 },
+    {   4,  3 },
+    {   3,  2 },
+    {   2,  1 },
+};
+
+static inline int get_ue_golomb(GetBitContext *gb) {
+    int i, v;
+    for (i = 0; i < 32 && !get_bits1(gb); i++)
+        ;
+    for (v = 1; i--;)
+        v = (v << 1) | get_bits1(gb);
+    return v - 1;
+}
+
+static inline int get_se_golomb(GetBitContext *gb) {
+    int v = get_ue_golomb(gb) + 1;
+    int sign = -(v & 1);
+    return ((v >> 1) ^ sign) - sign;
+}
+
+H264SequenceParameterSet *ff_avc_decode_sps(const uint8_t *buf, int buf_size)
+{
+    int i, j, ret, rbsp_size, aspect_ratio_idc, pic_order_cnt_type;
+    int num_ref_frames_in_pic_order_cnt_cycle;
+    int delta_scale, lastScale = 8, nextScale = 8;
+    int sizeOfScalingList;
+    H264SequenceParameterSet *sps = NULL;
+    GetBitContext gb;
+    uint8_t *rbsp_buf;
+
+    rbsp_buf = ff_nal_unit_extract_rbsp(buf, buf_size, &rbsp_size, 0);
+    if (!rbsp_buf)
+        return NULL;
+
+    ret = init_get_bits8(&gb, rbsp_buf, rbsp_size);
+    if (ret < 0)
+        goto end;
+
+    sps = av_mallocz(sizeof(*sps));
+    if (!sps)
+        goto end;
+
+    sps->profile_idc = get_bits(&gb, 8);
+    sps->constraint_set_flags |= get_bits1(&gb) << 0; // constraint_set0_flag
+    sps->constraint_set_flags |= get_bits1(&gb) << 1; // constraint_set1_flag
+    sps->constraint_set_flags |= get_bits1(&gb) << 2; // constraint_set2_flag
+    sps->constraint_set_flags |= get_bits1(&gb) << 3; // constraint_set3_flag
+    sps->constraint_set_flags |= get_bits1(&gb) << 4; // constraint_set4_flag
+    sps->constraint_set_flags |= get_bits1(&gb) << 5; // constraint_set5_flag
+    skip_bits(&gb, 2); // reserved_zero_2bits
+    sps->level_idc = get_bits(&gb, 8);
+    sps->id = get_ue_golomb(&gb);
+
+    if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
+        sps->profile_idc == 122 || sps->profile_idc == 244 || sps->profile_idc ==  44 ||
+        sps->profile_idc ==  83 || sps->profile_idc ==  86 || sps->profile_idc == 118 ||
+        sps->profile_idc == 128 || sps->profile_idc == 138 || sps->profile_idc == 139 ||
+        sps->profile_idc == 134) {
+        sps->chroma_format_idc = get_ue_golomb(&gb); // chroma_format_idc
+        if (sps->chroma_format_idc == 3) {
+            skip_bits1(&gb); // separate_colour_plane_flag
+        }
+        sps->bit_depth_luma = get_ue_golomb(&gb) + 8;
+        get_ue_golomb(&gb); // bit_depth_chroma_minus8
+        skip_bits1(&gb); // qpprime_y_zero_transform_bypass_flag
+        if (get_bits1(&gb)) { // seq_scaling_matrix_present_flag
+            for (i = 0; i < ((sps->chroma_format_idc != 3) ? 8 : 12); i++) {
+                if (!get_bits1(&gb)) // seq_scaling_list_present_flag
+                    continue;
+                lastScale = 8;
+                nextScale = 8;
+                sizeOfScalingList = i < 6 ? 16 : 64;
+                for (j = 0; j < sizeOfScalingList; j++) {
+                    if (nextScale != 0) {
+                        delta_scale = get_se_golomb(&gb);
+                        nextScale = (lastScale + delta_scale) & 0xff;
+                    }
+                    lastScale = nextScale == 0 ? lastScale : nextScale;
+                }
+            }
+        }
+    } else {
+        sps->chroma_format_idc = 1;
+        sps->bit_depth_luma = 8;
+    }
+
+    get_ue_golomb(&gb); // log2_max_frame_num_minus4
+    pic_order_cnt_type = get_ue_golomb(&gb);
+
+    if (pic_order_cnt_type == 0) {
+        get_ue_golomb(&gb); // log2_max_pic_order_cnt_lsb_minus4
+    } else if (pic_order_cnt_type == 1) {
+        skip_bits1(&gb);    // delta_pic_order_always_zero
+        get_se_golomb(&gb); // offset_for_non_ref_pic
+        get_se_golomb(&gb); // offset_for_top_to_bottom_field
+        num_ref_frames_in_pic_order_cnt_cycle = get_ue_golomb(&gb);
+        for (i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++)
+            get_se_golomb(&gb); // offset_for_ref_frame
+    }
+
+    get_ue_golomb(&gb); // max_num_ref_frames
+    skip_bits1(&gb); // gaps_in_frame_num_value_allowed_flag
+    get_ue_golomb(&gb); // pic_width_in_mbs_minus1
+    get_ue_golomb(&gb); // pic_height_in_map_units_minus1
+
+    sps->frame_mbs_only_flag = get_bits1(&gb);
+    if (!sps->frame_mbs_only_flag)
+        skip_bits1(&gb); // mb_adaptive_frame_field_flag
+
+    skip_bits1(&gb); // direct_8x8_inference_flag
+
+    if (get_bits1(&gb)) { // frame_cropping_flag
+        get_ue_golomb(&gb); // frame_crop_left_offset
+        get_ue_golomb(&gb); // frame_crop_right_offset
+        get_ue_golomb(&gb); // frame_crop_top_offset
+        get_ue_golomb(&gb); // frame_crop_bottom_offset
+    }
+
+    if (get_bits1(&gb)) { // vui_parameters_present_flag
+        if (get_bits1(&gb)) { // aspect_ratio_info_present_flag
+            aspect_ratio_idc = get_bits(&gb, 8);
+            if (aspect_ratio_idc == 0xff) {
+                sps->sar.num = get_bits(&gb, 16);
+                sps->sar.den = get_bits(&gb, 16);
+            } else if (aspect_ratio_idc < FF_ARRAY_ELEMS(avc_sample_aspect_ratio)) {
+                sps->sar = avc_sample_aspect_ratio[aspect_ratio_idc];
+            }
+        }
+    }
+
+    if (!sps->sar.den) {
+        sps->sar.num = 1;
+        sps->sar.den = 1;
+    }
+
+ end:
+    av_free(rbsp_buf);
+    return sps;
+}
diff --git a/libavformat/avc.h b/libavformat/avc.h
index c5e80ff650..a79bf9b2db 100644
--- a/libavformat/avc.h
+++ b/libavformat/avc.h
@@ -33,5 +33,20 @@  int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size);
 const uint8_t *ff_avc_mp4_find_startcode(const uint8_t *start,
                                          const uint8_t *end,
                                          int nal_length_size);
+uint8_t *ff_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len,
+                                  uint32_t *dst_len, int header_len);
+
+typedef struct {
+    uint8_t id;
+    uint8_t profile_idc;
+    uint8_t level_idc;
+    uint8_t constraint_set_flags;
+    uint8_t chroma_format_idc;
+    uint8_t bit_depth_luma;
+    uint8_t frame_mbs_only_flag;
+    AVRational sar;
+} H264SequenceParameterSet;
+
+H264SequenceParameterSet *ff_avc_decode_sps(const uint8_t *src, int src_len);
 
 #endif /* AVFORMAT_AVC_H */
diff --git a/libavformat/hevc.c b/libavformat/hevc.c
index 3628d5a028..c7c4be3441 100644
--- a/libavformat/hevc.c
+++ b/libavformat/hevc.c
@@ -643,40 +643,6 @@  static int hvcc_parse_pps(GetBitContext *gb,
     return 0;
 }
 
-static uint8_t *nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len,
-                                      uint32_t *dst_len)
-{
-    uint8_t *dst;
-    uint32_t i, len;
-
-    dst = av_malloc(src_len + AV_INPUT_BUFFER_PADDING_SIZE);
-    if (!dst)
-        return NULL;
-
-    /* NAL unit header (2 bytes) */
-    i = len = 0;
-    while (i < 2 && 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;
-}
-
-
-
 static void nal_unit_parse_header(GetBitContext *gb, uint8_t *nal_type)
 {
     skip_bits1(gb); // forbidden_zero_bit
@@ -753,7 +719,7 @@  static int hvcc_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size,
     uint8_t *rbsp_buf;
     uint32_t rbsp_size;
 
-    rbsp_buf = nal_unit_extract_rbsp(nal_buf, nal_size, &rbsp_size);
+    rbsp_buf = ff_nal_unit_extract_rbsp(nal_buf, nal_size, &rbsp_size, 2);
     if (!rbsp_buf) {
         ret = AVERROR(ENOMEM);
         goto end;
diff --git a/libavformat/mxf.h b/libavformat/mxf.h
index 4394450dea..f32124f772 100644
--- a/libavformat/mxf.h
+++ b/libavformat/mxf.h
@@ -48,6 +48,7 @@  enum MXFMetadataSetType {
     EssenceGroup,
     TaggedValue,
     TapeDescriptor,
+    AVCSubDescriptor,
 };
 
 enum MXFFrameLayout {
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index 8c6db94865..2bfef953fa 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -49,12 +49,14 @@ 
 #include "libavcodec/bytestream.h"
 #include "libavcodec/dnxhddata.h"
 #include "libavcodec/dv_profile.h"
-#include "libavcodec/h264.h"
+#include "libavcodec/h264_ps.h"
+#include "libavcodec/golomb.h"
 #include "libavcodec/internal.h"
 #include "audiointerleave.h"
 #include "avformat.h"
 #include "avio_internal.h"
 #include "internal.h"
+#include "avc.h"
 #include "mxf.h"
 #include "config.h"
 
@@ -99,6 +101,7 @@  typedef struct MXFStreamContext {
     int max_gop;             ///< maximum gop size, used by mpeg-2 descriptor
     int b_picture_count;     ///< maximum number of consecutive b pictures, used in mpeg-2 descriptor
     int low_delay;           ///< low delay, used in mpeg-2 descriptor
+    int avc_intra;
 } MXFStreamContext;
 
 typedef struct MXFContainerEssenceEntry {
@@ -167,6 +170,7 @@  static const struct {
 static void mxf_write_wav_desc(AVFormatContext *s, AVStream *st);
 static void mxf_write_aes3_desc(AVFormatContext *s, AVStream *st);
 static void mxf_write_mpegvideo_desc(AVFormatContext *s, AVStream *st);
+static void mxf_write_h264_desc(AVFormatContext *s, AVStream *st);
 static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st);
 static void mxf_write_generic_sound_desc(AVFormatContext *s, AVStream *st);
 static void mxf_write_s436m_anc_desc(AVFormatContext *s, AVStream *st);
@@ -310,7 +314,7 @@  static const MXFContainerEssenceEntry mxf_essence_container_uls[] = {
     { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,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,0x0a,0x04,0x01,0x02,0x02,0x01,0x00,0x00,0x00 },
-      mxf_write_mpegvideo_desc },
+      mxf_write_h264_desc },
     // S436M ANC
     { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x0D,0x01,0x03,0x01,0x02,0x0e,0x00,0x00 },
       { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x17,0x01,0x02,0x00 },
@@ -503,6 +507,13 @@  static const MXFLocalTagPair mxf_local_tag_batch[] = {
     { 0x3D0A, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x02,0x03,0x02,0x01,0x00,0x00,0x00}}, /* Block Align */
 };
 
+static const MXFLocalTagPair mxf_avc_subdescriptor_local_tags[] = {
+    { 0x8100, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x04,0x06,0x10,0x00,0x00}}, /* SubDescriptors */
+    { 0x8200, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x01,0x06,0x06,0x01,0x0E,0x00,0x00}}, /* AVC Decoding Delay */
+    { 0x8201, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x01,0x06,0x06,0x01,0x0A,0x00,0x00}}, /* AVC Profile */
+    { 0x8202, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x01,0x06,0x06,0x01,0x0D,0x00,0x00}}, /* AVC Level */
+};
+
 static const MXFLocalTagPair mxf_user_comments_local_tag[] = {
     { 0x4406, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x03,0x02,0x01,0x02,0x0C,0x00,0x00,0x00}}, /* User Comments */
     { 0x5001, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x03,0x02,0x01,0x02,0x09,0x01,0x00,0x00}}, /* Name */
@@ -584,15 +595,33 @@  static int mxf_get_essence_container_ul_index(enum AVCodecID id)
     return -1;
 }
 
+static void mxf_write_local_tags(AVIOContext *pb, const MXFLocalTagPair *local_tags, int count)
+{
+    int i;
+    for (i = 0; i < count; i++) {
+        avio_wb16(pb, local_tags[i].local_tag);
+        avio_write(pb, local_tags[i].uid, 16);
+    }
+}
+
 static void mxf_write_primer_pack(AVFormatContext *s)
 {
     MXFContext *mxf = s->priv_data;
     AVIOContext *pb = s->pb;
     int local_tag_number, i = 0;
+    int avc_tags_count = 0;
 
     local_tag_number = FF_ARRAY_ELEMS(mxf_local_tag_batch);
     local_tag_number += mxf->store_user_comments * FF_ARRAY_ELEMS(mxf_user_comments_local_tag);
 
+    for (i = 0; i < s->nb_streams; i++) {
+        MXFStreamContext *sc = s->streams[i]->priv_data;
+        if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_H264 && !sc->avc_intra) {
+            avc_tags_count = FF_ARRAY_ELEMS(mxf_avc_subdescriptor_local_tags);
+            local_tag_number += avc_tags_count;
+        }
+    }
+
     avio_write(pb, primer_pack_key, 16);
     klv_encode_ber_length(pb, local_tag_number * 18 + 8);
 
@@ -608,6 +637,8 @@  static void mxf_write_primer_pack(AVFormatContext *s)
             avio_wb16(pb, mxf_user_comments_local_tag[i].local_tag);
             avio_write(pb, mxf_user_comments_local_tag[i].uid, 16);
         }
+    if (avc_tags_count > 0)
+        mxf_write_local_tags(pb, mxf_avc_subdescriptor_local_tags, avc_tags_count);
 }
 
 static void mxf_write_local_tag(AVIOContext *pb, int size, int tag)
@@ -1126,6 +1157,8 @@  static const UID mxf_aes3_descriptor_key      = { 0x06,0x0E,0x2B,0x34,0x02,0x53,
 static const UID mxf_cdci_descriptor_key      = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x28,0x00 };
 static const UID mxf_generic_sound_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x42,0x00 };
 
+static const UID mxf_avc_subdescriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x6E,0x00 };
+
 static int get_trc(UID ul, enum AVColorTransferCharacteristic trc)
 {
     switch (trc){
@@ -1317,6 +1350,13 @@  static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID
         avio_w8(pb, sc->field_dominance);
     }
 
+    if (st->codecpar->codec_id == AV_CODEC_ID_H264 && !sc->avc_intra) {
+        // write avc sub descriptor ref
+        mxf_write_local_tag(pb, 8 + 16, 0x8100);
+        mxf_write_refs_count(pb, 1);
+        mxf_write_uuid(pb, AVCSubDescriptor, 0);
+    }
+
     return pos;
 }
 
@@ -1329,10 +1369,50 @@  static void mxf_update_klv_size(AVIOContext *pb, int64_t pos)
     avio_seek(pb, cur_pos, SEEK_SET);
 }
 
+static void mxf_write_avc_subdesc(AVFormatContext *s, AVStream *st)
+{
+    AVIOContext *pb = s->pb;
+    int64_t pos;
+
+    avio_write(pb, mxf_avc_subdescriptor_key, 16);
+    klv_encode_ber4_length(pb, 0);
+    pos = avio_tell(pb);
+
+    mxf_write_local_tag(pb, 16, 0x3C0A);
+    mxf_write_uuid(pb, AVCSubDescriptor, 0);
+
+    mxf_write_local_tag(pb, 1, 0x8200);
+    avio_w8(pb, 0xFF); // AVC Decoding Delay, unknown
+
+    mxf_write_local_tag(pb, 1, 0x8201);
+    avio_w8(pb, st->codecpar->profile); // AVC Profile
+
+    mxf_write_local_tag(pb, 1, 0x8202);
+    avio_w8(pb, st->codecpar->level); // AVC Level
+
+    mxf_update_klv_size(s->pb, pos);
+}
+
 static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st)
 {
     int64_t pos = mxf_write_cdci_common(s, st, mxf_cdci_descriptor_key);
     mxf_update_klv_size(s->pb, pos);
+
+    if (st->codecpar->codec_id == AV_CODEC_ID_H264) {
+        mxf_write_avc_subdesc(s, st);
+    }
+}
+
+static void mxf_write_h264_desc(AVFormatContext *s, AVStream *st)
+{
+    MXFStreamContext *sc = st->priv_data;
+    if (sc->avc_intra) {
+        mxf_write_mpegvideo_desc(s, st);
+    } else {
+        int64_t pos = mxf_write_cdci_common(s, st, mxf_cdci_descriptor_key);
+        mxf_update_klv_size(s->pb, pos);
+        mxf_write_avc_subdesc(s, st);
+    }
 }
 
 static void mxf_write_s436m_anc_desc(AVFormatContext *s, AVStream *st)
@@ -2136,30 +2216,30 @@  static const struct {
     int frame_size;
     int profile;
     uint8_t interlaced;
-    int long_gop; // 1 or 0 when there are separate UIDs for Long GOP and Intra, -1 when Intra/LGOP detection can be ignored
+    int intra_only; // 1 or 0 when there are separate UIDs for Long GOP and Intra, -1 when Intra/LGOP detection can be ignored
 } mxf_h264_codec_uls[] = {
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x11,0x01 },      0,  66, 0, -1 }, // AVC Baseline, Unconstrained Coding
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x11,0x01 },      0,  66, 0, -1 }, // AVC Baseline
     {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x20,0x01 },      0,  77, 0, -1 }, // AVC Main
     {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x30,0x01 },      0,  88, 0, -1 }, // AVC Extended
     {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x40,0x01 },      0, 100, 0, -1 }, // AVC High
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x50,0x01 },      0, 110, 0,  1 }, // AVC High 10
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x60,0x01 },      0, 122, 0,  1 }, // AVC High 422
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x70,0x01 },      0, 244, 0,  1 }, // AVC High 444
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x20,0x01 },      0, 110, 0,  0 }, // AVC High 10 Intra
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x01 }, 232960,   0, 1,  0 }, // AVC Intra 50 1080i60
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x02 }, 281088,   0, 1,  0 }, // AVC Intra 50 1080i50
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x03 }, 232960,   0, 0,  0 }, // AVC Intra 50 1080p30
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x04 }, 281088,   0, 0,  0 }, // AVC Intra 50 1080p25
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x08 }, 116736,   0, 0,  0 }, // AVC Intra 50 720p60
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x09 }, 140800,   0, 0,  0 }, // AVC Intra 50 720p50
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x30,0x01 },      0, 122, 0,  0 }, // AVC High 422 Intra
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x01 }, 472576,   0, 1,  0 }, // AVC Intra 100 1080i60
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x02 }, 568832,   0, 1,  0 }, // AVC Intra 100 1080i50
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x03 }, 472576,   0, 0,  0 }, // AVC Intra 100 1080p30
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x04 }, 568832,   0, 0,  0 }, // AVC Intra 100 1080p25
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x08 }, 236544,   0, 0,  0 }, // AVC Intra 100 720p60
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x09 }, 284672,   0, 0,  0 }, // AVC Intra 100 720p50
-    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0d,0x04,0x01,0x02,0x02,0x01,0x32,0x40,0x01 },      0, 244, 0,  0 }, // AVC High 444 Intra
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x50,0x01 },      0, 110, 0,  0 }, // AVC High 10
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x60,0x01 },      0, 122, 0,  0 }, // AVC High 422
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x70,0x01 },      0, 244, 0,  0 }, // AVC High 444
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x20,0x01 },      0, 110, 0,  1 }, // AVC High 10 Intra
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x01 }, 232960, 110, 1,  1 }, // AVC High 10 Intra RP2027 Class 50 1080/59.94i
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x02 }, 281088, 110, 1,  1 }, // AVC High 10 Intra RP2027 Class 50 1080/50i
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x03 }, 232960, 110, 0,  1 }, // AVC High 10 Intra RP2027 Class 50 1080/29.97p
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x04 }, 281088, 110, 0,  1 }, // AVC High 10 Intra RP2027 Class 50 1080/25p
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x08 }, 116736, 110, 0,  1 }, // AVC High 10 Intra RP2027 Class 50 720/59.94p
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x09 }, 140800, 110, 0,  1 }, // AVC High 10 Intra RP2027 Class 50 720/50p
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x30,0x01 },      0, 122, 0,  1 }, // AVC High 422 Intra
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x01 }, 472576, 122, 1,  1 }, // AVC High 422 Intra RP2027 Class 100 1080/59.94i
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x02 }, 568832, 122, 1,  1 }, // AVC High 422 Intra RP2027 Class 100 1080/50i
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x03 }, 472576, 122, 0,  1 }, // AVC High 422 Intra RP2027 Class 100 1080/29.97p
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x04 }, 568832, 122, 0,  1 }, // AVC High 422 Intra RP2027 Class 100 1080/25p
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x08 }, 236544, 122, 0,  1 }, // AVC High 422 Intra RP2027 Class 100 720/59.94p
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x09 }, 284672, 122, 0,  1 }, // AVC High 422 Intra RP2027 Class 100 720/50p
+    {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0d,0x04,0x01,0x02,0x02,0x01,0x32,0x40,0x01 },      0, 244, 0,  1 }, // AVC High 444 Intra
     {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0d,0x04,0x01,0x02,0x02,0x01,0x32,0x50,0x01 },      0,  44, 0, -1 }, // AVC CAVLC 444
 };
 
@@ -2168,37 +2248,70 @@  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]);
+    H264SequenceParameterSet *sps;
+    GetBitContext gb;
     const uint8_t *buf = pkt->data;
     const uint8_t *buf_end = pkt->data + pkt->size;
+    const uint8_t *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, frame_size, 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;
+
+            if (mxf->header_written)
+                break;
+
+            nal_end = ff_avc_find_startcode(buf, buf_end);
+            sps = ff_avc_decode_sps(buf, nal_end - buf);
+            if (!sps) {
+                av_log(s, AV_LOG_ERROR, "error parsing sps\n");
+                return 0;
+            }
+
+            sc->aspect_ratio.num = st->codecpar->width * sps->sar.num;
+            sc->aspect_ratio.den = st->codecpar->height * 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 = (sps->constraint_set_flags >> 3) & 1;
+            sc->interlaced = !sps->frame_mbs_only_flag;
+            sc->component_depth = sps->bit_depth_luma;
+
+            buf = nal_end;
             break;
         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_bits8(&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 +2320,37 @@  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 (!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;
+            mxf->cbr_index = 1;
+            sc->frame_size = frame_size;
             if (sc->interlaced)
                 sc->field_dominance = 1; // top field first is mandatory for AVC Intra
-            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))) {
+            break;
+        } else if (sps && mxf_h264_codec_uls[i].frame_size == 0 &&
+                   mxf_h264_codec_uls[i].profile == 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 = sps->profile_idc;
+            st->codecpar->level = sps->level_idc;
+            // continue to check for avc intra
         }
     }
 
-    if (!uid_found) {
+    av_free(sps);
+
+    if (!sc->codec_ul) {
         av_log(s, AV_LOG_ERROR, "h264 profile not supported\n");
         return 0;
     }