Result_t
AS_02::MXF::AS02IndexReader::InitFromFile(const Kumu::FileReader& reader, const ASDCP::MXF::RIP& rip, const bool has_header_essence)
{
  typedef std::list<Kumu::mem_ptr<ASDCP::MXF::Partition> > body_part_array_t;
  body_part_array_t body_part_array;
  body_part_array_t::const_iterator body_part_iter;

  ASDCP::MXF::Array<ASDCP::MXF::RIP::Pair>::const_iterator i;
  Result_t result = m_IndexSegmentData.Capacity(128*Kumu::Kilobyte); // will be grown if needed
  ui32_t first_body_sid = 0;

  // create a list of body parts and index parts
  for ( i = rip.PairArray.begin(); KM_SUCCESS(result) && i != rip.PairArray.end(); ++i )
    {
      if ( i->BodySID == 0 )
	continue;

      if ( first_body_sid == 0 )
	{
	  first_body_sid = i->BodySID;
	}
      else if ( i->BodySID != first_body_sid )
	{
	  DefaultLogSink().Debug("The index assembler is ignoring BodySID %d.\n", i->BodySID);
	  continue;
	}

      reader.Seek(i->ByteOffset);
      ASDCP::MXF::Partition *this_partition = new ASDCP::MXF::Partition(m_Dict);
      assert(this_partition);

      result = this_partition->InitFromFile(reader);

      if ( KM_FAILURE(result) )
	{
	  delete this_partition;
	  return result;
	}

      if ( this_partition->BodySID != i->BodySID )
	{
	  DefaultLogSink().Error("Partition BodySID %d does not match RIP BodySID %d.\n",
				 this_partition->BodySID, i->BodySID);
	}

      body_part_array.push_back(0);
      body_part_array.back().set(this_partition);
    }

  if ( body_part_array.empty() )
    {
      DefaultLogSink().Error("File has no partitions with essence data.\n");
      return RESULT_AS02_FORMAT;
    }

  body_part_iter = body_part_array.begin();

  for ( i = rip.PairArray.begin(); KM_SUCCESS(result) && i != rip.PairArray.end(); ++i )
    {
      reader.Seek(i->ByteOffset);
      ASDCP::MXF::Partition plain_part(m_Dict);
      result = plain_part.InitFromFile(reader);

      if ( KM_FAILURE(result) )
	return result;

      if ( plain_part.IndexByteCount > 0 )
	{
	  if ( body_part_iter == body_part_array.end() )
	    {
	      DefaultLogSink().Error("Index and Body partitions do not match.\n");
	      break;
	    }

	  if ( plain_part.ThisPartition == plain_part.FooterPartition )
	    {
	      DefaultLogSink().Warn("File footer partition contains index data.\n");
	    }

	  // slurp up the remainder of the partition
	  ui32_t read_count = 0;

	  assert (plain_part.IndexByteCount <= 0xFFFFFFFFL);
	  ui32_t bytes_this_partition = (ui32_t)plain_part.IndexByteCount;

	  result = m_IndexSegmentData.Capacity(m_IndexSegmentData.Length() + bytes_this_partition);

	  if ( KM_SUCCESS(result) )
	    result = reader.Read(m_IndexSegmentData.Data() + m_IndexSegmentData.Length(),
				 bytes_this_partition, &read_count);

	  if ( KM_SUCCESS(result) && read_count != bytes_this_partition )
	    {
	      DefaultLogSink().Error("Short read of index partition: got %u, expecting %u\n",
				     read_count, bytes_this_partition);
	      return RESULT_AS02_FORMAT;
	    }

	  if ( KM_SUCCESS(result) )
	    {
	      ui64_t current_body_offset = 0;
	      ui64_t current_ec_offset = 0;
	      assert(body_part_iter != body_part_array.end());

	      assert(!body_part_iter->empty());
	      ASDCP::MXF::Partition *tmp_partition = body_part_iter->get();

	      if ( has_header_essence && tmp_partition->ThisPartition == 0 )
		{
		  current_body_offset = 0;
		  current_ec_offset = tmp_partition->HeaderByteCount + tmp_partition->ArchiveSize();
		}
	      else
		{
		  current_body_offset = tmp_partition->BodyOffset;
		  current_ec_offset += tmp_partition->ThisPartition + tmp_partition->ArchiveSize();
		}

	      result = InitFromBuffer(m_IndexSegmentData.RoData() + m_IndexSegmentData.Length(), bytes_this_partition, current_body_offset, current_ec_offset);
	      m_IndexSegmentData.Length(m_IndexSegmentData.Length() + bytes_this_partition);
	      ++body_part_iter;
	    }
	}
    }

  if ( KM_SUCCESS(result) )
    {
      std::list<InterchangeObject*>::const_iterator ii;
  
      for ( ii = m_PacketList->m_List.begin(); ii != m_PacketList->m_List.end(); ++ii )
	{
	  IndexTableSegment *segment = dynamic_cast<IndexTableSegment*>(*ii);

	  if ( segment != 0 )
	    {
	      m_Duration += segment->IndexDuration;
	    }
	}
    }

#if 0
  char identbuf[IdentBufferLen];
  std::list<InterchangeObject*>::iterator j;
  std::vector<ASDCP::MXF::IndexTableSegment::IndexEntry>::iterator k;
  ui32_t entry_count = 0;

  for ( j = m_PacketList->m_List.begin(); j != m_PacketList->m_List.end(); ++j )
    {
      assert(*j);
      ASDCP::MXF::IndexTableSegment* segment = static_cast<ASDCP::MXF::IndexTableSegment*>(*j);

      fprintf(stderr, "  --------------------------------------\n");
      fprintf(stderr, "  IndexEditRate      = %d/%d\n",  segment->IndexEditRate.Numerator, segment->IndexEditRate.Denominator);
      fprintf(stderr, "  IndexStartPosition = %s\n",  i64sz(segment->IndexStartPosition, identbuf));
      fprintf(stderr, "  IndexDuration      = %s\n",  i64sz(segment->IndexDuration, identbuf));
      fprintf(stderr, "  EditUnitByteCount  = %u\n",  segment->EditUnitByteCount);
      fprintf(stderr, "  IndexSID           = %u\n",  segment->IndexSID);
      fprintf(stderr, "  BodySID            = %u\n",  segment->BodySID);
      fprintf(stderr, "  SliceCount         = %hu\n", segment->SliceCount);
      fprintf(stderr, "  PosTableCount      = %hu\n", segment->PosTableCount);
      fprintf(stderr, "  RtFileOffset       = %s\n",  i64sz(segment->RtFileOffset, identbuf));
      fprintf(stderr, "  RtEntryOffset      = %s\n",  i64sz(segment->RtEntryOffset, identbuf));
      fprintf(stderr, "  IndexEntryArray:\n");

      for ( k = segment->IndexEntryArray.begin(); k != segment->IndexEntryArray.end(); ++k )
	{
	  fprintf(stderr, "  0x%010qx\n", k->StreamOffset);
	  ++entry_count;
	}
    }

  fprintf(stderr, "Actual entries: %d\n", entry_count);
#endif

  return result;
}
Beispiel #2
0
// TODO: refactor to use InitFromBuffer
ASDCP::Result_t
ASDCP::KLVFilePacket::InitFromFile(const Kumu::FileReader& Reader)
{
  ui32_t read_count;
  byte_t tmp_data[tmp_read_size];
  ui64_t tmp_size;
  m_KeyStart = m_ValueStart = 0;
  m_KLLength = m_ValueLength = 0;
  m_Buffer.Size(0);

  Result_t result = Reader.Read(tmp_data, tmp_read_size, &read_count);

  if ( ASDCP_FAILURE(result) )
    return result;

  if ( read_count < (SMPTE_UL_LENGTH + 1) )
    {
      DefaultLogSink().Error("Short read of Key and Length got %u\n", read_count);
      return RESULT_READFAIL;
    }

  if ( memcmp(tmp_data, SMPTE_UL_START, 4) != 0 )
    {
      DefaultLogSink().Error("Unexpected UL preamble: %02x.%02x.%02x.%02x\n",
			     tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]);
      return RESULT_FAIL;
    }

  if ( ! Kumu::read_BER(tmp_data + SMPTE_UL_LENGTH, &tmp_size) )
    {
      DefaultLogSink().Error("BER Length decoding error\n");
      return RESULT_FAIL;
    }

  if ( tmp_size > MAX_KLV_PACKET_LENGTH )
    {
      Kumu::ui64Printer tmp_size_str(tmp_size);
      DefaultLogSink().Error("Packet length %s exceeds internal limit\n", tmp_size_str.c_str());
      return RESULT_FAIL;
    }

  ui32_t remainder = 0;
  ui32_t ber_len = Kumu::BER_length(tmp_data + SMPTE_UL_LENGTH);
  m_KLLength = SMPTE_UL_LENGTH + ber_len;
  assert(tmp_size <= 0xFFFFFFFFL);
  m_ValueLength = (ui32_t) tmp_size;
  ui32_t packet_length = m_ValueLength + m_KLLength;

  result = m_Buffer.Capacity(packet_length);

  if ( ASDCP_FAILURE(result) )
    return result;

  m_KeyStart = m_Buffer.Data();
  m_ValueStart = m_Buffer.Data() + m_KLLength;
  m_Buffer.Size(packet_length);

  // is the whole packet in the tmp buf?
  if ( packet_length <= tmp_read_size )
    {
      assert(packet_length <= read_count);
      memcpy(m_Buffer.Data(), tmp_data, packet_length);

      if ( (remainder = read_count - packet_length) != 0 )
	{
	  DefaultLogSink().Warn("Repositioning pointer for short packet\n");
	  Kumu::fpos_t pos = Reader.Tell();
	  assert(pos > remainder);
	  result = Reader.Seek(pos - remainder);
	}
    }
  else
    {
      if ( read_count < tmp_read_size )
	{
	  DefaultLogSink().Error("Short read of packet body, expecting %u, got %u\n",
				 m_Buffer.Size(), read_count);
	  return RESULT_READFAIL;
	}

      memcpy(m_Buffer.Data(), tmp_data, tmp_read_size);
      remainder = m_Buffer.Size() - tmp_read_size;

      if ( remainder > 0 )
	{
	  result = Reader.Read(m_Buffer.Data() + tmp_read_size, remainder, &read_count);
      
	  if ( read_count != remainder )
	    {
	      DefaultLogSink().Error("Short read of packet body, expecting %u, got %u\n",
				     remainder+tmp_read_size, read_count+tmp_read_size);
	      result = RESULT_READFAIL;
	    }
	}
    }

  return result;
}