+static const struct {
+ UID uid;
+ int frame_size;
+ int profile;
+ uint8_t interlaced;
+} mxf_h264_codec_uls[] = {
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x20,0x01 }, 0, 110, 0 }, // AVC High 10 Intra
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x01 }, 232960, 0, 1 }, // AVC Intra 50 1080i60
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x02 }, 281088, 0, 1 }, // AVC Intra 50 1080i50
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x03 }, 232960, 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 }, // AVC Intra 50 1080p25
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x08 }, 116736, 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 }, // AVC Intra 50 720p50
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x30,0x01 }, 0, 122, 0 }, // AVC High 422 Intra
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x01 }, 472576, 0, 1 }, // AVC Intra 100 1080i60
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x02 }, 568832, 0, 1 }, // AVC Intra 100 1080i50
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x03 }, 472576, 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 }, // AVC Intra 100 1080p25
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x08 }, 236544, 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 }, // AVC Intra 100 720p50
+};
+
+static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st,
+ AVPacket *pkt, MXFIndexEntry *e)
+{
+ MXFContext *mxf = s->priv_data;
+ MXFStreamContext *sc = st->priv_data;
+ static const int mxf_h264_num_codec_uls = sizeof(mxf_h264_codec_uls) / sizeof(mxf_h264_codec_uls[0]);
+ const uint8_t *buf = pkt->data;
+ const uint8_t *buf_end = pkt->data + pkt->size;
+ uint32_t state = -1;
+ 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
+
+ for (;;) {
+ buf = avpriv_find_start_code(buf, buf_end, &state);
+ if (buf >= buf_end)
+ break;
+ --buf;
+ switch (state & 0x1f) {
+ case NAL_SPS:
+ st->codec->profile = buf[1];
+ e->flags |= 0x40;
+ break;
+ case NAL_PPS:
+ if (e->flags & 0x40) { // sequence header present
+ e->flags |= 0x80; // random access
+ extra_size = 0;
+ buf = buf_end;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (mxf->header_written)
+ return 1;
+
+ sc->aspect_ratio = (AVRational){ 16, 9 }; // 16:9 is mandatory for broadcast HD
+ sc->component_depth = 10; // AVC Intra is always 10 Bit
+ sc->interlaced = st->codec->field_order != AV_FIELD_PROGRESSIVE ? 1 : 0;
+ if (sc->interlaced)
+ sc->field_dominance = 1; // top field first is mandatory for AVC Intra
+
+ uid_found = 0;
+ frame_size = pkt->size + extra_size;
+ for (i = 0; i < mxf_h264_num_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;
+ return 1;
+ } else if (st->codec->profile == mxf_h264_codec_uls[i].profile) {
+ sc->codec_ul = &mxf_h264_codec_uls[i].uid;
+ uid_found = 1;
+ }
+ }
+
+ if (!uid_found) {
+ av_log(s, AV_LOG_ERROR, "AVC Intra 50/100 supported only\n");
+ return 0;
+ }
+
+ return 1;
+}
+