public synchronized boolean waitForState(int state) {
      switch (state) {
        case Processor.Configured:
          p.configure();
          break;
        case Controller.Realized:
          p.realize();
          break;
        case Controller.Prefetched:
          p.prefetch();
          break;
        case Controller.Started:
          p.start();
          break;
      }

      while (p.getState() < state && !error) {
        try {
          wait(1000);
        } catch (Exception e) {
        }
      }
      // p.removeControllerListener(this);
      return !(error);
    }
  /** With the given processor info generated from matchTracks, build each of the processors. */
  public boolean buildTracks(ProcInfo pInfo[]) {
    ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW);
    Processor p;

    for (int i = 0; i < pInfo.length; i++) {
      p = pInfo[i].p;
      p.setContentDescriptor(cd);

      // We are done with programming the processor. Let's just
      // realize the it.
      if (!waitForState(p, Controller.Realized)) {
        System.err.println("- Failed to realize the processor.");
        return false;
      }

      // Set the JPEG quality to .5.
      setJPEGQuality(p, 0.5f);

      PushBufferStream pbs[];
      TrackInfo tInfo;
      int trackID;

      // Cheating. I should have checked the type of DataSource
      // returned.
      pInfo[i].ds = (PushBufferDataSource) p.getDataOutput();
      pbs = pInfo[i].ds.getStreams();

      // Find the matching data stream for the given track for audio.

      for (int type = AUDIO; type < MEDIA_TYPES; type++) {
        for (trackID = 0; trackID < pInfo[i].numTracksByType[type]; trackID++) {
          tInfo = pInfo[i].tracksByType[type][trackID];
          tInfo.pbs = pbs[tInfo.idx];
        }
      }
    }

    return true;
  }
  /** Create the DataSink. */
  DataSink createDataSink(Processor p, MediaLocator outML) {
    DataSource ds;

    if ((ds = p.getDataOutput()) == null) {
      System.err.println(
          "Something is really wrong: the processor does not have an output DataSource");
      return null;
    }

    DataSink dsink;

    try {
      System.err.println("- Create DataSink for: " + outML);
      dsink = Manager.createDataSink(ds, outML);
      dsink.open();
    } catch (Exception e) {
      System.err.println("Cannot create the DataSink: " + e);
      return null;
    }

    return dsink;
  }
 StateWaiter(Processor p) {
   this.p = p;
   p.addControllerListener(this);
 }
  /**
   * Given an array of input media locators and an output locator, this method will concatenate the
   * input media files to generate a single concatentated output.
   */
  public boolean doIt(MediaLocator inML[], MediaLocator outML) {
    // Guess the output content descriptor from the file extension.
    ContentDescriptor cd;

    if ((cd = fileExtToCD(outML.getRemainder())) == null) {
      System.err.println("Couldn't figure out from the file extension the type of output needed!");
      return false;
    }

    // Build the ProcInfo data structure for each processor.
    ProcInfo pInfo[] = new ProcInfo[inML.length];

    for (int i = 0; i < inML.length; i++) {
      pInfo[i] = new ProcInfo();
      pInfo[i].ml = inML[i];

      try {
        System.err.println("- Create processor for: " + inML[i]);
        pInfo[i].p = Manager.createProcessor(inML[i]);
      } catch (Exception e) {
        System.err.println("Yikes!  Cannot create a processor from the given url: " + e);
        return false;
      }
    }

    // Try to match the tracks from different processors.
    if (!matchTracks(pInfo, cd)) {
      System.err.println("Failed to match the tracks.");
      return false;
    }

    // Program each processors to perform the necessary transcoding
    // to concatenate the tracks.
    if (!buildTracks(pInfo)) {
      System.err.println("Failed to build processors for the inputs.");
      return false;
    }

    // Generate a super glue data source from the processors.
    SuperGlueDataSource ds = new SuperGlueDataSource(pInfo);

    // Create the processor to generate the final output.
    Processor p;
    try {
      p = Manager.createProcessor(ds);
    } catch (Exception e) {
      System.err.println("Failed to create a processor to concatenate the inputs.");
      return false;
    }

    p.addControllerListener(this);

    // Put the Processor into configured state.
    if (!waitForState(p, Processor.Configured)) {
      System.err.println("Failed to configure the processor.");
      return false;
    }

    // Set the output content descriptor on the final processor.
    System.err.println("- Set output content descriptor to: " + cd);
    if ((p.setContentDescriptor(cd)) == null) {
      System.err.println("Failed to set the output content descriptor on the processor.");
      return false;
    }

    // We are done with programming the processor. Let's just
    // realize it.
    if (!waitForState(p, Controller.Realized)) {
      System.err.println("Failed to realize the processor.");
      return false;
    }

    // Now, we'll need to create a DataSink.
    DataSink dsink;
    if ((dsink = createDataSink(p, outML)) == null) {
      System.err.println("Failed to create a DataSink for the given output MediaLocator: " + outML);
      return false;
    }

    dsink.addDataSinkListener(this);
    fileDone = false;

    System.err.println("- Start concatenation...");

    // OK, we can now start the actual concatenation.
    try {
      p.start();
      dsink.start();
    } catch (IOException e) {
      System.err.println("IO error during concatenation");
      return false;
    }

    // Wait for EndOfStream event.
    waitForFileDone();

    // Cleanup.
    try {
      dsink.close();
    } catch (Exception e) {
    }
    p.removeControllerListener(this);

    System.err.println("  ...done concatenation.");

    return true;
  }