Exemplo n.º 1
0
/*----------------------------------------------------------------------
|   AP4_Processor::MuxStream
+---------------------------------------------------------------------*/
AP4_Result
AP4_Processor::MuxStream(
	AP4_Array<AP4_ByteStream *> &input,
	AP4_ByteStream& output,
	AP4_UI08		partitions,
	AP4_AtomFactory& atom_factory)
{
	AP4_Result		result;
	AP4_UI64		stream_offset = 0;

	if (partitions & 1)
	{
		// read all atoms.
		// keep all atoms except [mdat]
		// keep a ref to [moov]
		// put [moof] atoms in a separate list
		AP4_AtomParent              top_level;
		AP4_Array<AP4_MoovAtom*>	moov;
		AP4_Size					track_count(0);

		for(AP4_Size streamid(0); streamid < input.ItemCount(); ++streamid)
		{
			for (AP4_Atom* atom = NULL; AP4_SUCCEEDED(atom_factory.CreateAtomFromStream(*input[streamid], atom)); input[streamid]->Tell(stream_offset))
			{
				if (atom->GetType() == AP4_ATOM_TYPE_MFRA) {
					delete atom;
					continue;
				}
				else if (atom->GetType() == AP4_ATOM_TYPE_SIDX) {
					delete atom;
					continue;
				}
				else if (atom->GetType() == AP4_ATOM_TYPE_SSIX) {
					delete atom;
					continue;
				}
				if (streamid == 0)
					top_level.AddChild(atom);
				else if (atom->GetType() != AP4_ATOM_TYPE_MOOV)
					delete atom;
				if (atom->GetType() == AP4_ATOM_TYPE_MOOV)
				{
					moov.Append(AP4_DYNAMIC_CAST(AP4_MoovAtom,atom));
					break;
				}
			}
			if (moov.ItemCount() == streamid)
				return AP4_ERROR_INVALID_FORMAT;
			
			while (AP4_SUCCEEDED(moov[streamid]->DeleteChild(AP4_ATOM_TYPE_PSSH, 0)));

			// Remove tracks we cannot handle
			for (AP4_List<AP4_TrakAtom>::Item *item(moov[streamid]->GetTrakAtoms().FirstItem()); item;)
				if (!item->GetData()->FindChild("mdia/minf/stbl"))
					moov[streamid]->GetTrakAtoms().Remove(item);
				else
					item = item->GetNext();
			track_count += moov[streamid]->GetTrakAtoms().ItemCount();
		}

		// initialize the processor
		if (AP4_FAILED(result = Initialize(top_level, *input[0]))) 
			return result;

		// process the tracks if we have a moov atom
		m_TrackData.SetItemCount(track_count);
		m_StreamData.SetItemCount(input.ItemCount());
	
		//NormalizeTREX(mvex, 0, m_TrackCounts[0], m_TrackCounts[1]);
		AP4_Cardinal internal_index(0);
		AP4_ContainerAtom *mvex_base(0);
		AP4_List<AP4_TrakAtom>::Item *item = NULL;

		for (AP4_Size streamid(0); streamid < input.ItemCount(); ++streamid)
		{
			m_StreamData[streamid].trackStart = internal_index;
			m_StreamData[streamid].stream = input[streamid];
			if (streamid)
				moov[0]->AddTrakAtoms(moov[streamid]->GetTrakAtoms(), item);
			else
				item = moov[streamid]->GetTrakAtoms().FirstItem();

			for (; item; item = item->GetNext())
			{
				PERTRACK &track_data(m_TrackData[internal_index]);
				track_data.original_id = item->GetData()->GetId();
				item->GetData()->SetId(track_data.new_id = internal_index + 1);

        if (AP4_MdhdAtom* mdhd = AP4_DYNAMIC_CAST(AP4_MdhdAtom, item->GetData()->FindChild("mdia/mdhd")))
          track_data.timescale = mdhd->GetTimeScale();
        else
          track_data.timescale = 1;
        
        AP4_ContainerAtom *mvex = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moov[streamid]->GetChild(AP4_ATOM_TYPE_MVEX, 0));
				if (!mvex)
					return AP4_ERROR_INVALID_FORMAT;
				
				if (!item->GetData()->GetDuration())
				{
					AP4_MehdAtom *mehd(AP4_DYNAMIC_CAST(AP4_MehdAtom, mvex->GetChild(AP4_ATOM_TYPE_MEHD, 0)));
					item->GetData()->SetDuration(mehd? mehd->GetDuration():0);
				}
				
				AP4_TrexAtom *trex(NULL);
				unsigned int index(0);
				for (; !trex && (trex = AP4_DYNAMIC_CAST(AP4_TrexAtom, mvex->GetChild(AP4_ATOM_TYPE_TREX, index++)));)
					if(trex->GetTrackId() != track_data.original_id)
						trex = NULL;
				if (!trex)
					return AP4_ERROR_INVALID_FORMAT;

				if (mvex_base)
				{
					trex = AP4_DYNAMIC_CAST(AP4_TrexAtom, trex->Clone());
					mvex_base->AddChild(trex);
				}
				else
					mvex_base = mvex;
				trex->SetTrackId(track_data.new_id);

				track_data.track_handler = CreateTrackHandler(item->GetData(), trex);
				track_data.track_handler->ProcessTrack();
				track_data.streamId = streamid;
				++m_StreamData[streamid].trackCount;
				++internal_index;
			}
		}
		// We don't need the other moovs anymore.....
		moov.SetItemCount(1);

		AP4_MvhdAtom *mvhd(AP4_DYNAMIC_CAST(AP4_MvhdAtom, moov[0]->GetChild(AP4_ATOM_TYPE_MVHD, 0)));
		if (!mvhd->GetDuration())
		{
			AP4_MehdAtom *mehd(AP4_DYNAMIC_CAST(AP4_MehdAtom, mvex_base->GetChild(AP4_ATOM_TYPE_MEHD, 0)));
			mvhd->SetDuration(mehd ? mehd->GetDuration() : 0);
		}

		// finalize the processor
		Finalize(top_level);

		// calculate the size of all atoms combined
		AP4_UI64 atoms_size = 0;
		top_level.GetChildren().Apply(AP4_AtomSizeAdder(atoms_size));

		// write all atoms
		top_level.GetChildren().Apply(AP4_AtomListWriter(output));
		m_MoovAtom = moov[0];
		m_MoovAtom->Detach();
	}

	if (partitions & 2)
	{
		// process the fragments, if any
		result = AP4_SUCCESS;
		AP4_Array<AP4_UI64> moof_positions, mdat_positions;
		moof_positions.SetItemCount(input.ItemCount());
		mdat_positions.SetItemCount(input.ItemCount());

		for (;;)
		{
			AP4_ContainerAtom *moof = NULL;
			AP4_UI32 track_index(0);
			
#if 0			
      for (AP4_Cardinal streamid(0); streamid < input.ItemCount(); ++streamid)
			{
				AP4_Atom* atom = NULL;
				if (AP4_SUCCEEDED(input[streamid]->Tell(stream_offset)) && AP4_SUCCEEDED(atom_factory.CreateAtomFromStream(*input[streamid], atom)))
				{
					if (atom->GetType() != AP4_ATOM_TYPE_MOOF)
						return AP4_ERROR_INVALID_FORMAT;
					
					moof_positions[streamid] = stream_offset;
					mdat_positions[streamid] = stream_offset + atom->GetSize() + +AP4_ATOM_HEADER_SIZE;

					if (moof)
					{
						int index(0);
						for (; AP4_Atom* child = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom)->GetChild(AP4_ATOM_TYPE_TRAF, index++);)
							moof->AddChild(child->Clone());
						delete atom;
					}
					else
						moof = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
					NormalizeTRAF(AP4_DYNAMIC_CAST(AP4_ContainerAtom, moof), m_StreamData[streamid].trackStart,
						m_StreamData[streamid].trackStart + m_StreamData[streamid].trackCount, track_index);
				}
				else
					delete atom;
			}
#else
      double mindts(9999999999.0);
      AP4_Cardinal nextStream(~0);
      for (AP4_Cardinal track(0); track < m_TrackData.ItemCount(); ++track)
        if ((double)m_TrackData[track].dts / m_TrackData[track].timescale  < mindts)
        {
          mindts = (double)m_TrackData[track].dts / m_TrackData[track].timescale;
          nextStream = m_TrackData[track].streamId;
        }
      
      AP4_Atom* atom = NULL;
      if (AP4_SUCCEEDED(result = input[nextStream]->Tell(stream_offset)) && AP4_SUCCEEDED(result = atom_factory.CreateAtomFromStream(*input[nextStream], atom)))
      {
        if (atom->GetType() != AP4_ATOM_TYPE_MOOF)
          return AP4_ERROR_INVALID_FORMAT;
			} else if (atom)
				return result;

      moof_positions[nextStream] = stream_offset;
      mdat_positions[nextStream] = stream_offset + atom->GetSize() + +AP4_ATOM_HEADER_SIZE;

      moof = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
      NormalizeTRAF(AP4_DYNAMIC_CAST(AP4_ContainerAtom, moof), m_StreamData[nextStream].trackStart,
        m_StreamData[nextStream].trackStart + m_StreamData[nextStream].trackCount, track_index);
#endif
			if (!moof)
				break;
			
			if (AP4_FAILED(result = ProcessFragment(moof, NULL, 0, output, moof_positions, mdat_positions)))
				return result;
			
			delete moof;
			moof = NULL;
		}

		// cleanup
		m_TrackData.Clear();
		m_StreamData.Clear();
	}

	return AP4_SUCCESS;
}
Exemplo n.º 2
0
TTree* GrowJoinedPhotonTree( RAT::DSReader& theDS )
{
	//Now we build the fundamental blocks of our operation.  The TrackedOpticalPhoton is static to avoid
	//building many copies of the object on the stack, which is unnecessary.  We reset the photon at the
	//end of each track for this reason.
	RAT::DS::Root* theDSEvent = NULL;
	RAT::DS::MC* theDSMC = NULL;
	static TrackedOpticalPhoton thePhoton;
	TTree* theResultingTree = new TTree("T",
										"Data From Tracked Optical Photons");

//For ROOT compatibility.  For versions 5.22 and up, it's legal to omit the
//name of the class in this call.  Before then, we need to call it by name.
#ifdef __ROOTVERLT522
	TBranch* theBranch = theResultingTree->Branch("TrackedOpticalPhotons",
										"TrackedOpticalPhoton",&thePhoton);
#else 
	TBranch* theBranch = theResultingTree->Branch("TrackedOpticalPhotons",
											&thePhoton);
#endif
	//This is just to keep the compiler from complaining about the use of the
	//TBranch.
	theBranch->UpdateAddress();
	
	//All we are going to do, for starters, is get the tracks, print out the 
	//steps, join the tracks, and print them out again.  Easy stuff.  This will
	//also give an easy way to track where the code is going wrong (or right).
	for ( int eventIndex = 0; eventIndex < theDS.GetTotal(); eventIndex++  )
	{
		//Move to the next event.
		theDSEvent = theDS.GetEvent(eventIndex);
		theDSMC = theDSEvent->GetMC();
#ifndef CLUSTER_RUN
		//Spit out Event Info...
		std::cout << std::endl << "Analyzing event " << eventIndex << std::endl;
#endif		
		//The container will be a map, where the key is the trackID and the 
		//value is the track itself.  This structure is _very_ useful for 
		//track reconstruction, where you want to be able to get a track by
		//referring to its id.
		IDtoTrackMap tracks;
		
		//We also want to have a container that can tell us if a given track
		//caused a hit in the simulation.  We use a vector<bool>, where the
		//index is equal to the trackID.
		std::vector<bool> hit_list( theDSMC->GetMCTrackCount(), false );
		
		//Now fill the map with the tracks.
		for ( int track = 0; track < theDSMC->GetMCTrackCount(); track++ )
		{
			//Check if the track is an optical photon.
			if ( theDSMC->GetMCTrack(track)->GetParticleName() == "opticalphoton" )
			{
				//Grab the track out of the monte carlo and push it into the map
				//with its ID.
				RAT::DS::MCTrack newTrack = *theDSMC->GetMCTrack(track);
				tracks.insert( IDwithTrack(newTrack.GetTrackID(), newTrack) );
			}
		}
		
		//And now for every hit in the monte carlo, flip the appropriate bit.
		for ( int mc_pmt_hit = 0; mc_pmt_hit < theDSMC->GetMCPMTCount(); mc_pmt_hit++ )
		{
			//Iterate through all MCPhotons, flipping the TrackID'th bit in the vector<bool>
			//to indicate a hit.
			for ( int mc_phot = 0; mc_phot < theDSMC->GetMCPMT(mc_pmt_hit)->GetMCPhotonCount(); mc_phot++ )
			{	
				hit_list[ theDSMC->GetMCPMT(mc_pmt_hit)->GetMCPhoton(mc_phot)->GetTrackID() - 1 ].flip();
			}
		}
#ifndef CLUSTER_RUN
#ifdef PRINT_TRACK_DEBUG	
		//Now that our map is full of tracks, let's iterate over them and
		//print out their information.  This is, of course, pre-joining.
		IDtoTrackMap::iterator track_it = tracks.begin();
		while ( track_it != tracks.end() )
		{
			std::cout << "Track ID " << track_it->first << "->Child of track ID " << track_it->second.GetParentID() << "\n";
			for ( std::size_t stepcount = 0; stepcount < track_it->second.GetMCTrackStepCount(); stepcount++ )
			{
				std::cout << "\t Step " << stepcount << "->" << track_it->second.GetMCTrackStep(stepcount)->GetProcess() << "\n" 
					  << "\t\t X:" << track_it->second.GetMCTrackStep(stepcount)->GetEndpoint().X() << "\n"
					  << "\t\t Y:" << track_it->second.GetMCTrackStep(stepcount)->GetEndpoint().Y() << "\n"
					  << "\t\t Z:" << track_it->second.GetMCTrackStep(stepcount)->GetEndpoint().Z() << "\n"
					  << "\t\t T:" << track_it->second.GetMCTrackStep(stepcount)->GetGlobalTime() <<   "\n"
					  << "\t\t KE:" << track_it->second.GetMCTrackStep(stepcount)->GetKE() << std::endl;
			}
			//Remember to increment the iterator!
			track_it++;
		}
#endif
#endif		
		//OK, now the hard work.  We need to join these damn tracks.  Use a 
		//reverse iterator to move back through the tracks and look for child-
		//parent relationships.  This will simplify the logic of removing tracks 
		//from the map that 'belong' to some parent.
		IDtoTrackMap::reverse_iterator track_rit = tracks.rbegin();
		while ( track_rit != tracks.rend() )
		{
			//Search for the ID of the parent track in the map.  If it is found,
			//we have work to do.
			IDtoTrackMap::iterator mall_guard = tracks.find( track_rit->second.GetParentID() );
			if ( mall_guard != tracks.end() )
			{
				//Create a vector of the tracks that are related, and start looking
				//to see if they have parents of their own.
				std::vector<RAT::DS::MCTrack> estranged_tracks;
				estranged_tracks.push_back( mall_guard->second );
				estranged_tracks.push_back( track_rit->second );
				
				mall_guard = tracks.find( mall_guard->second.GetParentID() );
				while ( mall_guard != tracks.end() )
				{
					estranged_tracks.push_back( mall_guard->second );
					mall_guard = tracks.find( mall_guard->second.GetParentID() );
				}
				//Now here's the trick.  The original tracks need to be 
				//__removed__ from the track listing.  Otherwise, when we step
				//to the next track, we are going to have issues due to the 
				//fact that they are tracks in the chain.  Of course, this is
				//fine, because we have retained all of the information they
				//had anyhow.  While we are doing this, we want to check to see
				//if any of the tracks caused hits in the monte carlo.  If they
				//did, we need to flip the new bit in the hitlist.
				std::vector<RAT::DS::MCTrack>::iterator est_it = estranged_tracks.begin();
				bool ChildHit(false);
				while ( est_it != estranged_tracks.end() )
				{
					unsigned theChildID = est_it->GetTrackID();
					if ( hit_list[theChildID - 1] ) 
					{
						//Mark the flag and unset the hitlist for the child.
						ChildHit = true;
						hit_list[theChildID - 1].flip();
					}
					tracks.erase( tracks.find(theChildID)->first );
					est_it++;
				}
				//Now we should have all of the parents.  Assemble them via
				//the JoinMCTracks function.  For now, just stick it on the end
				//of the tracks we've already made.
				
				RAT::DS::MCTrack joined = JoinMCTracks(estranged_tracks);
				tracks.insert( IDwithTrack(joined.GetTrackID(),joined) );
				
				//If the ChildHit bit is flipped, make sure that the trackID of
				//the new joined track gets set.
				if ( ChildHit ) hit_list[ joined.GetTrackID() - 1 ].flip();

				//Now the iterator needs to be reset, because we've deleted elements
				//from the map, which _should_ invalidate the pointer, but it 
				//doesn't because find() returns a forward iterator.
				track_rit = tracks.rbegin();
			}
			else track_rit++;
		}
#ifndef CLUSTER_RUN		
#ifdef PRINT_TRACK_DEBUG
		//Post-joined info.
		track_it = tracks.begin();
		std::cout << "----------CORRECTED TRACKS FOLLOW----------" << std::endl;
		while ( track_it != tracks.end() )
		{
			std::cout << "Track ID " << track_it->second.GetTrackID() << "->Child of track ID " << track_it->second.GetParentID() << "\n";
			for ( std::size_t stepcount = 0; stepcount < track_it->second.GetMCTrackStepCount(); stepcount++ )
			{
				std::cout << "\t Step " << stepcount << "->" << track_it->second.GetMCTrackStep(stepcount)->GetProcess() << "\n" 
				<< "\t\t X:" << track_it->second.GetMCTrackStep(stepcount)->GetEndpoint().X() << "\n"
				<< "\t\t Y:" << track_it->second.GetMCTrackStep(stepcount)->GetEndpoint().Y() << "\n"
				<< "\t\t Z:" << track_it->second.GetMCTrackStep(stepcount)->GetEndpoint().Z() << "\n"
				<< "\t\t T:" << track_it->second.GetMCTrackStep(stepcount)->GetGlobalTime() <<   "\n"
				<< "\t\t KE:" << track_it->second.GetMCTrackStep(stepcount)->GetKE() << std::endl;
			}
			//Remember to increment the iterator!
			track_it++;
		}
#endif
#endif
		//Now the tracks that were split by reemissions etc have been rejoined.  We
		//are therefore free to do the analysis on them.  Using the map iterator to
		//jump through the tracks should be easiest and fastest
#ifndef PRINT_TRACK_DEBUG
		//If the debug flag wasn't set, this iterator won't be in memory.
        //So we declare it here.
        IDtoTrackMap::iterator track_it;
#endif
		std::cout << tracks.size() << " reconstructed tracks found." << std::endl;
		track_it = tracks.begin();
		
		//A counter so we can build in a progress indicator.
		std::size_t track_index(1);
		while ( track_it != tracks.end() )
		{
#ifndef CLUSTER_RUN
			std::cout << track_index << " of " << tracks.size() << " processed.\r" << std::flush;
#endif
			//First set the proper event index for this photon.
			thePhoton.fEventNo = eventIndex;
			
			//tracks.front() object is the track we are working with!  It is in no particular spatial or temporal
			//order, but that is immaterial.
			RAT::DS::MCTrack curTrack = track_it->second;
			thePhoton.fParentID = curTrack.GetParentID();
			//Set the birthplace for this track.
			thePhoton.fBirthX = curTrack.GetMCTrackStep(0)->GetEndpoint().X();
			thePhoton.fBirthY = curTrack.GetMCTrackStep(0)->GetEndpoint().Y();
			thePhoton.fBirthZ = curTrack.GetMCTrackStep(0)->GetEndpoint().Z();
			thePhoton.totalLength = curTrack.GetLength();
			//Now check the trackID against the list of known hits.
			if ( hit_list[curTrack.GetTrackID() - 1] == true ) thePhoton.MarkDefiniteHit();
		
			//Boundary and process checking.
			static std::string currentProcess("");
			static bool LastStepEndedOnBoundary(false);
			
			//Since this is the beginning, we can figure out what process generated this track.
			std::string parentProcess = curTrack.GetMCTrackStep(0)->GetProcess();
			if ( parentProcess == "Scintillation" ) thePhoton.isScintillation = true;
			else if ( parentProcess == "Cerenkov" ) thePhoton.isCerenkov = true;
			
			//Now onto the step checks.
			for ( int step_index = 0; step_index < curTrack.GetMCTrackStepCount(); step_index++ )
			{
				//Get the current step and set the process variable.
				RAT::DS::MCTrackStep curStep = *curTrack.GetMCTrackStep(step_index);
				currentProcess = curStep.GetProcess();
				
				//If the last step ended on a boundary...
				if ( LastStepEndedOnBoundary && step_index != 0 )
				{
					//This will track the totally internally reflected photons.
					//To actually capture the step that reflects, we need to get
					//the last photon back!
					if ( curStep.GetEndVolume() == curTrack.GetMCTrackStep(step_index-1)->GetVolume() ) 
					{
						RAT::DS::MCTrackStep temp_track_step = *curTrack.GetMCTrackStep(step_index-1);
						thePhoton.AddReflection( temp_track_step.GetEndpoint().X(),
									 temp_track_step.GetEndpoint().Y(),
									 temp_track_step.GetEndpoint().Z(),
									 temp_track_step.GetGlobalTime()  );
					}
				}				
		
				//This will check if the current step is involved in a process that can
				//lead to a hit being recorded in the monte carlo.  It is no guarantee that
				//it is actually a hit (a definite hit), as that is determined probabilistically at
				//(simulation) runtime.  Therefore this is called an indefinite hit.  Not all 
				//indefinite hits are definite hits, but all definite hits are indefinite hits.
				if ( currentProcess.find("G4FastSimulationManagerProcess") != std::string::npos ) 
				{
					thePhoton.AddPMTHit( curStep.GetEndpoint().X(),
							     curStep.GetEndpoint().Y(),
							     curStep.GetEndpoint().Z(),
							     curStep.GetGlobalTime() );
				}
				
				//This is the process accounting step.  If the photon was reemitted, mark it.
				if ( currentProcess == "Reemission" )
				{
					//If we haven't already marked this photon as being reemitted, mark it.
					if ( thePhoton.isReemitted == false ) thePhoton.isReemitted = true;
					thePhoton.ReemissionCount++;					
				}
				
				//If this step ended on a boundary, then the StepStatus will mark it as fGeomBoundary.
				//During the next step, we can check if this flag was set, and if so, do reflection
				//checking.  If it didn't, but the flag is set from the previous step, unset it.
				if ( curStep.GetStepStatus() == "GeomBoundary" ) LastStepEndedOnBoundary = true;
				else if ( LastStepEndedOnBoundary ) LastStepEndedOnBoundary = false;
			}
			
			//We've done all of the necessary steps, so on to filling the tree and
			//finishing the iteration.
			theResultingTree->Fill();
			thePhoton.Reset();	
			//To finish this iteration, just increment the map iterator and
			//the track counter.
			track_it++;
			track_index++;
		}
	}
		
	//Now just return the tree we built.
#ifndef CLUSTER_RUN
#endif
	return theResultingTree;
}