/// <summary> /// Make sure all the streams for this StreamMgr have compatible compressed media types. /// Also check against the media type, optionally supplied as an argument. /// Log details about any problems we find. /// </summary> /// In no-recompression scenarios including the preview we check this and warn the user, /// though we can't do anything about it. /// <param name="prevMT">An additional MediaType to check against, or null if none</param> /// <param name="log">Where to write details about any problems found</param> /// <returns>always true</returns> public bool ValidateCompressedMT(MediaType prevMT, LogMgr log) { MediaType lastMT = prevMT; for (int i = 0; i < streamPlayers.Length; i++) { if (payload == PayloadType.dynamicVideo) { if (!ProfileUtility.CompareVideoMediaTypes((MediaTypeVideoInfo)streamPlayers[i].StreamMediaType, (MediaTypeVideoInfo)lastMT)) { Debug.WriteLine("incompatible video mediatype found."); log.WriteLine("Warning: A change in the media type was found in the video stream from " + this.cname + " beginning at " + streamPlayers[i].Start.ToString() + ". Without recompression, this may cause " + " a problem with the output. Using recompression should resolve the issue. "); log.ErrorLevel = 5; } } else if (payload == PayloadType.dynamicAudio) { if (!ProfileUtility.CompareAudioMediaTypes((MediaTypeWaveFormatEx)streamPlayers[i].StreamMediaType, (MediaTypeWaveFormatEx)lastMT)) { Debug.WriteLine("incompatible mediatype found."); log.WriteLine("Warning: A change in the media type was found in the audio stream from " + this.cname + " beginning at " + streamPlayers[i].Start.ToString() + ". Without recompression, this may cause " + " a problem with the output. Using recompression should resolve the issue. "); log.ErrorLevel = 5; } } lastMT = streamPlayers[i].StreamMediaType; } return(true); }
/// <summary> /// Assume that all the StreamMgrs provided are configured with the correct time range. Do not assume /// contiguous data, or compatible media types. /// </summary> /// <param name="audioMgr"></param> /// <param name="log"></param> public AudioMixer(StreamMgr[] audioMgr, LogMgr log) { fileStreamPlayer = null; this.audioMgr = audioMgr; this.log = log; refTime = long.MinValue; inbufs = new ArrayList(); if (audioMgr.Length == 0) { return; } /// Examine the uncompressed MT's for each audioMgr, and implement a voting system so that the /// media type that is dominant for this mixer is the one we use, and other incompatible MT's /// are ignored in the mix. Log a warning at places where the MT changes. /// Remember that each audioMgr may itself have multiple FileStreamPlayers which have different uncompressed /// media types. /// Finally we need to make our uncompressed MT available to the caller for use in configuring the writer. /// Later on let's look at ways to convert any common uncompressed types so that they are compatible. AudioCompatibilityMgr audioCompatibilityMgr = new AudioCompatibilityMgr(); foreach (StreamMgr astream in audioMgr) { astream.CheckUncompressedAudioTypes(audioCompatibilityMgr); } this.uncompressedMediaType = audioCompatibilityMgr.GetDominantType(); String warning = audioCompatibilityMgr.GetWarningString(); if (warning != "") { log.WriteLine(warning); log.ErrorLevel = 5; } incompatibleGuids = audioCompatibilityMgr.GetIncompatibleGuids(); // Here we also want to collect a "native" (compressed) profile corresponding to one of the "compatible" // streams. This is useful in case we need to recompress. Note this profile can be created if we have // a stream ID. compatibleStreamID = audioCompatibilityMgr.GetCompatibleStreamID(); this.bitsPerSample = this.uncompressedMediaType.WaveFormatEx.BitsPerSample; this.bytesPerSample = bitsPerSample / 8; this.ticksPerSample = ((uint)Constants.TicksPerSec) / (this.uncompressedMediaType.WaveFormatEx.SamplesPerSec * this.uncompressedMediaType.WaveFormatEx.Channels); limit = (long)((ulong)1 << (int)bitsPerSample) / 2 - 1; //clip level buffers = new SampleBuffer[audioMgr.Length]; for (int i = 0; i < buffers.Length; i++) { buffers[i] = new SampleBuffer(audioMgr[i], ticksPerSample, incompatibleGuids, this.uncompressedMediaType.WaveFormatEx.Channels); } }
public SlideStreamMgr(ArchiveTranscoderJob job, ArchiveTranscoderJobSegment segment, LogMgr logMgr, double fps, int width, int height) { this.job = job; this.segment = segment; this.logMgr = logMgr; if (width > 0 && height > 0) { this.outputWidth = width; this.outputHeight = height; } this.ticksBetweenFrames = (long)((double)Constants.TicksPerSec / fps); uncompressedMT = getUncompressedMT(this.outputWidth, this.outputHeight, fps); cancel = false; initialized = false; pptInstalled = Utility.CheckPptIsInstalled(); if ((!DateTime.TryParse(segment.StartTime, out start)) || (!DateTime.TryParse(segment.EndTime, out end))) { throw(new System.Exception("Failed to parse start/end time")); } this.nextFrameTime = start.Ticks; format = Utility.StringToPresenterWireFormatType(segment.PresentationDescriptor.PresentationFormat); payload = Utility.formatToPayload(format); cname = segment.PresentationDescriptor.PresentationCname; slideImageMgr = new SlideImageMgr(format, this.outputWidth, this.outputHeight); //Get the start time for the entire conference and use that to get streams. long confStart = DatabaseUtility.GetConferenceStartTime(payload, cname, start.Ticks, end.Ticks); if (confStart <= 0) { logMgr.WriteLine("Warning: No conference exists in the database that matches this presentation: " + cname + " with PresentationFormat " + format.ToString()); logMgr.ErrorLevel = 7; confStart = start.Ticks; } //Get the relevant stream_id's and create DBStreamPlayers for each. streamIDs = DatabaseUtility.GetStreams(payload, segment.PresentationDescriptor.PresentationCname, null, confStart, end.Ticks); DateTime sdt = new DateTime(confStart); Debug.WriteLine("***Conference start: " + sdt.ToString() + " end: " + end.ToString()); if ((streamIDs == null) || (streamIDs.Length == 0)) { Debug.WriteLine("No presentation data found."); logMgr.WriteLine("Warning: No presentation data was found for the given time range for " + cname + " with PresentationFormat " + format.ToString()); logMgr.ErrorLevel = 7; streamPlayers = null; return; } streamPlayers = new DBStreamPlayer[streamIDs.Length]; for (int i = 0; i < streamIDs.Length; i++) { streamPlayers[i] = new DBStreamPlayer(streamIDs[i], confStart, end.Ticks, payload); } lookBehindDuration = 0; if (streamPlayers[0].Start < start) { lookBehindDuration = ((TimeSpan)(start - streamPlayers[0].Start)).TotalSeconds; } }
/// <summary> /// Build a list of slide decks referenced in the job, and generate a directory of slide images for each deck. /// </summary> public void Process() { progressTracker.CustomMessage = "Processing Slides"; progressTracker.CurrentValue = 0; //build a list of decks from the job spec Hashtable workList = new Hashtable(); log.WriteLine("Generating Slide Images."); foreach (ArchiveTranscoderJobSegment segment in job.Segment) { if (segment.SlideDecks != null) { foreach (ArchiveTranscoderJobSlideDeck deck in segment.SlideDecks) { Guid deckGuid = new Guid(deck.DeckGuid); if (this.outputDirs.ContainsKey(deckGuid)) { //Deck was previously converted. continue; } if (!workList.ContainsKey(deckGuid)) { if (deck.Path == null) { //unmatched deck log.WriteLine("Warning: Specified deck has not been matched to a file: " + deck.Title); log.ErrorLevel = 5; continue; } FileInfo fi = new FileInfo(deck.Path); if (fi.Exists) { workList.Add(deckGuid, fi); } else { DirectoryInfo di = new DirectoryInfo(deck.Path); if (di.Exists) { workList.Add(deckGuid, di); } else { log.WriteLine("Warning: Specified deck does not exist: " + fi.FullName); log.ErrorLevel = 5; } } } else if (deck.Path != ((FileInfo)workList[deckGuid]).FullName) { log.WriteLine("Warning: The same deck was specified with different paths: " + deck.Path + " " + ((FileInfo)workList[deckGuid]).FullName); log.ErrorLevel = 3; } } } } log.WriteLine("Found " + workList.Count.ToString() + " deck(s) in the job."); //Since it is impractical to find out how many slides are in each deck here, we will consider each deck to //be worth 100 in progressTracker. int deckCount = workList.Count; if (rtDocuments != null) { deckCount += rtDocuments.Count; } if (slideMessages != null) { //For now we ignore these since there are assumed to be just a few at most. } progressTracker.EndValue = deckCount * 100; //Build image directory for each deck if (workList.Count > 0) { int currentDeck = 0; foreach (Guid g in workList.Keys) { if (workList[g] is FileInfo) { if (((FileInfo)workList[g]).FullName.ToLower().IndexOf(".ppt", 1) > 0) { if (Utility.CheckPptIsInstalled()) { if (this.useNativeJpegExport || this.usePPTImageExport) { // Use Powerpoint directly to do the image export processPpt(g, (FileInfo)workList[g]); } else { // Use CP3 to open the PPT file and do the export processPptWithCp3(g, (FileInfo)workList[g]); } } else { log.WriteLine("Warning: A PowerPoint deck was specified, but PowerPoint does not appear to be " + "installed on this system. This deck will be ignored: " + ((FileInfo)workList[g]).FullName + " To resolve this problem specify a CSD deck in the job, " + "or run Archive Transcoder on a system with PowerPoint installed."); log.ErrorLevel = 5; } } else if (((FileInfo)workList[g]).FullName.ToLower().IndexOf(".csd", 1) > 0) { processCsd(g, (FileInfo)workList[g]); } else if (((FileInfo)workList[g]).FullName.ToLower().IndexOf(".cp3", 1) > 0) { processCp3(g, (FileInfo)workList[g]); } else { log.WriteLine("Warning: unsupported deck file type: " + ((FileInfo)workList[g]).FullName + " This deck will be ignored."); log.ErrorLevel = 5; } } else if (workList[g] is DirectoryInfo) { processDir(g, (DirectoryInfo)workList[g]); } currentDeck++; } } if (pptApp != null) { if (!pptAlreadyOpen) { try { pptApp.Quit(); } catch { } } pptApp = null; GC.Collect(); } if ((!stopNow) && (this.rtDocuments != null)) { foreach (Guid g in rtDocuments.Keys) { processRTDocument((RTDocument)rtDocuments[g]); } } if ((!stopNow) && (this.slideMessages != null)) { foreach (String s in slideMessages.Keys) { processSlideMessage((WorkSpace.SlideMessage)slideMessages[s]); } } }