func: static int mxf_read_header(AVFormatContext *s)
  
  {
  
      MXFContext *mxf = s->priv_data;
  
      KLVPacket klv;
  
      int64_t essence_offset = 0;
  
      int ret;
  
  
  
      mxf->last_forward_tell = INT64_MAX;
  
      mxf->edit_units_per_packet = 1;
  
  
  
      if (!mxf_read_sync(s->pb, mxf_header_partition_pack_key, 14)) {
  
          av_log(s, AV_LOG_ERROR, "could not find header partition pack key\n");
  
          return AVERROR_INVALIDDATA;
  
      }
  
      avio_seek(s->pb, -14, SEEK_CUR);
  
      mxf->fc = s;
  
      mxf->run_in = avio_tell(s->pb);
  
  
  
      while (!url_feof(s->pb)) {
  
          const MXFMetadataReadTableEntry *metadata;
  
  
  
          if (klv_read_packet(&klv, s->pb) < 0) {
  
              /* EOF - seek to previous partition or stop */
  
              if(mxf_parse_handle_partition_or_eof(mxf) <= 0)
  
                  break;
  
              else
  
                  continue;
  
          }
  
  
  
          PRINT_KEY(s, "read header", klv.key);
  
          av_dlog(s, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset);
  
          if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key) ||
  
              IS_KLV_KEY(klv.key, mxf_essence_element_key) ||
  
              IS_KLV_KEY(klv.key, mxf_avid_essence_element_key) ||
  
              IS_KLV_KEY(klv.key, mxf_system_item_key)) {
  
  
  
              if (!mxf->current_partition) {
  
                  av_log(mxf->fc, AV_LOG_ERROR, "found essence prior to first PartitionPack\n");
  
                  return AVERROR_INVALIDDATA;
  
              }
  
  
  
              if (!mxf->current_partition->essence_offset) {
  
                  /* for OP1a we compute essence_offset
  
                   * for OPAtom we point essence_offset after the KL (usually op1a_essence_offset + 20 or 25)
  
                   * TODO: for OP1a we could eliminate this entire if statement, always stopping parsing at op1a_essence_offset
  
                   *       for OPAtom we still need the actual essence_offset though (the KL's length can vary)
  
                   */
  
                  int64_t op1a_essence_offset =
  
                      round_to_kag(mxf->current_partition->this_partition +
  
                                   mxf->current_partition->pack_length,       mxf->current_partition->kag_size) +
  
                      round_to_kag(mxf->current_partition->header_byte_count, mxf->current_partition->kag_size) +
  
                      round_to_kag(mxf->current_partition->index_byte_count,  mxf->current_partition->kag_size);
  
  
  
                  if (mxf->op == OPAtom) {
  
                      /* point essence_offset to the actual data
  
                      * OPAtom has all the essence in one big KLV
  
                      */
  
                      mxf->current_partition->essence_offset = avio_tell(s->pb);
  
                      mxf->current_partition->essence_length = klv.length;
  
                  } else {
  
                      /* NOTE: op1a_essence_offset may be less than to klv.offset (C0023S01.mxf)  */
  
                      mxf->current_partition->essence_offset = op1a_essence_offset;
  
                  }
  
              }
  
  
  
              if (!essence_offset)
  
                  essence_offset = klv.offset;
  
  
  
              /* seek to footer, previous partition or stop */
  
              if (mxf_parse_handle_essence(mxf) <= 0)
  
                  break;
  
              continue;
  
          } else if (!memcmp(klv.key, mxf_header_partition_pack_key, 13) &&
  
                     klv.key[13] >= 2 && klv.key[13] <= 4 && mxf->current_partition) {
  
              /* next partition pack - keep going, seek to previous partition or stop */
  
              if(mxf_parse_handle_partition_or_eof(mxf) <= 0)
  
                  break;
  
              else if (mxf->parsing_backward)
  
                  continue;
  
              /* we're still parsing forward. proceed to parsing this partition pack */
  
          }
  
  
  
          for (metadata = mxf_metadata_read_table; metadata->read; metadata++) {
  
              if (IS_KLV_KEY(klv.key, metadata->key)) {
  
                  int res;
  
                  if (klv.key[5] == 0x53) {
  
                      res = mxf_read_local_tags(mxf, &klv, metadata->read, metadata->ctx_size, metadata->type);
  
                  } else {
  
                      uint64_t next = avio_tell(s->pb) + klv.length;
  
                      res = metadata->read(mxf, s->pb, 0, klv.length, klv.key, klv.offset);
  
  
  
                      /* only seek forward, else this can loop for a long time */
  
                      if (avio_tell(s->pb) > next) {
  
                          av_log(s, AV_LOG_ERROR, "read past end of KLV @ %#"PRIx64"\n",
  
                                 klv.offset);
  
                          return AVERROR_INVALIDDATA;
  
                      }
  
  
  
                      avio_seek(s->pb, next, SEEK_SET);
  
                  }
  
                  if (res < 0) {
  
                      av_log(s, AV_LOG_ERROR, "error reading header metadata\n");
  
                      return res;
  
                  }
  
                  break;
  
              }
  
          }
  
          if (!metadata->read)
  
              avio_skip(s->pb, klv.length);
  
      }
  
      /* FIXME avoid seek */
  
      if (!essence_offset)  {
  
          av_log(s, AV_LOG_ERROR, "no essence\n");
  
          return AVERROR_INVALIDDATA;
  
      }
  
      avio_seek(s->pb, essence_offset, SEEK_SET);
  
  
  
      mxf_compute_essence_containers(mxf);
  
  
  
      /* we need to do this before computing the index tables
  
       * to be able to fill in zero IndexDurations with st->duration */
  
      if ((ret = mxf_parse_structural_metadata(mxf)) < 0)
  
          return ret;
  
  
  
      if ((ret = mxf_compute_index_tables(mxf)) < 0)
  
          return ret;
  
  
  
      if (mxf->nb_index_tables > 1) {
  
          /* TODO: look up which IndexSID to use via EssenceContainerData */
  
          av_log(mxf->fc, AV_LOG_INFO, "got %i index tables - only the first one (IndexSID %i) will be used\n",
  
                 mxf->nb_index_tables, mxf->index_tables[0].index_sid);
  
      } else if (mxf->nb_index_tables == 0 && mxf->op == OPAtom) {
  
          av_log(mxf->fc, AV_LOG_ERROR, "cannot demux OPAtom without an index\n");
  
          return AVERROR_INVALIDDATA;
  
      }
  
  
  
      mxf_handle_small_eubc(s);
  
  
  
      return 0;
  
  }
  