/// <summary>
        /// Stop the encoding process
        /// </summary>
        public void Stop()
        {
            if (cam != null)
            {
                cam.Pause();
            }
            if (mic != null)
            {
                mic.Pause();
            }
            EncoderRunning = false;

            if (coreloops != null)
            {
                foreach (var loop in coreloops)
                {
                    loop.Join();                     // wait for the encoder to get the message and actually stop. Easier than screwing it's state data.
                }
            }
            try { cam.Dispose(); } catch { }
            try { mic.Dispose(); } catch { }

            foreach (var pkg in Packages)
            {
                try {
                    EncoderBridge.CloseEncoderJob(ref pkg.Job);
                } catch { }
            }
            if (outputRouter != null)
            {
                outputRouter.Close();
            }
        }
        /// <summary>
        /// This loop does the actual work of reading caches into the encoder and firing actions.
        /// This loop controls Multiple-bit-rate encoding
        /// </summary>
        private void EncoderCoreLoop(object Package)
        {
            EncoderPackage pkg = Package as EncoderPackage;

            try {
                #region Start up
                if (pkg == null)
                {
                    throw new Exception("Encoder core loop package was lost");
                }
                double lastVideoTime = 0.0;                 // used for Adaptive frame rate

                if (cam != null)
                {
                    lastVideoTime = cam.TimecodeStart;
                }

                int loop_frame_incr = 0;
                if (pkg.Specification.HasVideo)
                {
                    loop_frame_incr = 1;
                    videoJobs++;
                }
                #endregion

                while (!EncoderRunning)                   // wait for the signal!
                {
                    System.Threading.Thread.Sleep(1000);
                }

                WaitForSyncFlag();

                start = DateTime.Now;
                while (EncoderRunning)                   // Encode frames until stopped
                {
                    #region Frame availability checks
                    // Wait for buffers to be populated
                    while (pkg.BuffersEmpty(MinimumBufferPopulation) && EncoderRunning)
                    {
                        foreach (var buf in pkg.Buffers)
                        {
                            buf.RebufferCapturedFrames();
                        }
                        if (pkg.BuffersEmpty(MinimumBufferPopulation))
                        {
                            System.Threading.Thread.Sleep(frameSleep);
                        }
                    }

                    if (DryRun)
                    {
                        System.Threading.Thread.Sleep(frameSleep);
                        continue;                         // don't encode
                    }
                    #endregion

                    pkg.LoadAllBuffers();
                    EncoderBridge.EncodeFrame(ref pkg.Job, ref pkg.Frame);
                    pkg.UnloadAllBuffers();

                    if (!pkg.Job.IsValid)
                    {
                        throw new Exception("Job became invalid. Possible memory or filesystem error");
                    }

                    #region Segment switching
                    if (pkg.Job.SegmentNumber != pkg.Job.OldSegmentNumber)
                    {
                        double real_chunk_duration = pkg.Frame.VideoSampleTime - lastVideoTime;
                        lock (outputRouter) {
                            outputRouter.NewChunkAvailable(pkg.Job.OldSegmentNumber, pkg.JobIndex, real_chunk_duration);
                        }
                        lastVideoTime            = pkg.Frame.VideoSampleTime;
                        pkg.Job.OldSegmentNumber = pkg.Job.SegmentNumber;
                    }

                    FrameCount += loop_frame_incr;
                    #endregion
                }
            } catch (Exception ex) {
                System.Diagnostics.Debug.Fail("EncoderController.cs: Core loop fault.", ex.Message + "\r\n" + ex.StackTrace);

                File.WriteAllText(config.EncoderSettings.LocalSystemOutputFolder + @"/error.txt", "Main loop: " + ex.Message + "\r\n" + ex.StackTrace);
            } finally {
                if (pkg != null)
                {
                    EncoderBridge.CloseEncoderJob(ref pkg.Job);                    // NEVER FORGET THIS!!
                }
                if (EncoderRunning)
                {
                    Halt();                                 // Don't use 'Stop()' in the core loop, or the system will freeze!
                }
                System.Threading.Thread.CurrentThread.Abort();
            }
        }