</Reference>\r
</ItemGroup>\r
<ItemGroup>\r
+ <Compile Include="DxPlayer - Copy.cs" />\r
<Compile Include="DxPlayer.cs" />\r
<Compile Include="FilterGraphTools.cs" />\r
<Compile Include="FlexibleMessageBox.cs" />\r
</Compile>\r
<Compile Include="Messages.cs" />\r
<Compile Include="NativeMethods.cs" />\r
+ <Compile Include="PlayerGraph.cs" />\r
<Compile Include="Program.cs" />\r
<Compile Include="Properties\Resources.Designer.cs">\r
<DependentUpon>Resources.resx</DependentUpon>\r
--- /dev/null
+using System;\r
+using System.Drawing;\r
+using System.Runtime.InteropServices;\r
+using System.Diagnostics;\r
+using System.Windows.Forms;\r
+using System.Threading;\r
+\r
+using DirectShowLib;\r
+using DirectShowLib.Utils;\r
+using Microsoft.Win32.SafeHandles;\r
+using System.ComponentModel;\r
+using System.Drawing.Imaging;\r
+using System.Drawing.Drawing2D;\r
+using System.Collections.Generic;\r
+using Myriadbits.MXF;\r
+using MaestroShared.Metadata;\r
+using NLog;\r
+\r
+namespace DxPlay {\r
+\r
+ internal class DxPlayerx : ISampleGrabberCB, IDisposable {\r
+ private static readonly Logger logger = LogManager.GetCurrentClassLogger();\r
+\r
+ [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory")]\r
+ private static extern void CopyMemory(IntPtr Destination, IntPtr Source, [MarshalAs(UnmanagedType.U4)] uint Length);\r
+\r
+ private const int MEDIATIME_REFERENCE = 10000000;\r
+\r
+ public enum GraphState {\r
+ Stopped,\r
+ Completed,\r
+ Paused,\r
+ Playing,\r
+ Exiting\r
+ }\r
+\r
+ public Dictionary<GraphState, string> stateHunStringValues = new Dictionary<GraphState, string>();\r
+\r
+ public MediaDescription MediaDescription { get; internal set; }\r
+ public Timecode CurrentTC { get; internal set; }\r
+ public GraphState State { get; internal set; }\r
+\r
+ private IFilterGraph2 m_FilterGraph;\r
+ private IMediaControl m_mediaCtrl;\r
+ private IMediaEvent m_mediaEvent;\r
+\r
+ // Event used by Media Event thread\r
+ private ManualResetEvent m_mre;\r
+ private BackgroundWorker tcWorker;\r
+ // Current state of the graph (can change async)\r
+\r
+ public event DxPlayEvent PlayEvent;\r
+ public delegate void DxPlayEvent();\r
+\r
+ private Thread m_eventThread = null;\r
+ private IMediaSeeking m_mediaSeek = null;\r
+\r
+ private IVideoWindow m_videoWindow = null;\r
+ private IBaseFilter m_videoRenderer = null;\r
+ private object tcLock = new object();\r
+ Bitmap m_Bitmap = null;\r
+ public bool IsError { get; set; }\r
+#if DEBUG\r
+ // Allow you to "Connect to remote graph" from GraphEdit\r
+ DsROTEntry m_DsRot;\r
+#endif\r
+ private int m_stride;\r
+\r
+ // Release everything.\r
+ public void Dispose() {\r
+ CloseInterfaces();\r
+ }\r
+\r
+ ~DxPlayerx() {\r
+ CloseInterfaces();\r
+ }\r
+\r
+ Control playerWindow;\r
+ private object ppUnk;\r
+\r
+ // Play an avi file into a window. Allow for snapshots.\r
+ // (Control to show video in, Avi file to play\r
+ public DxPlayerx(Control hWin, ref MediaDescription mediaDesc) {\r
+ FillTheHunStringvalues();\r
+ State = GraphState.Stopped;\r
+ try {\r
+ int hr;\r
+ IntPtr hEvent;\r
+ MediaDescription = mediaDesc;\r
+ // Set up the graph\r
+ playerWindow = hWin;\r
+\r
+ SetupGraph();\r
+\r
+ hWin.Hide();\r
+ hWin.Show();\r
+\r
+ // Get the event handle the graph will use to signal\r
+ // when events occur\r
+ Debug.WriteLine("GetEventHandle");\r
+ hr = m_mediaEvent.GetEventHandle(out hEvent);\r
+ DsError.ThrowExceptionForHR(hr);\r
+\r
+ // Wrap the graph event with a ManualResetEvent\r
+ m_mre = new ManualResetEvent(false);\r
+ m_mre.SafeWaitHandle = new SafeWaitHandle(hEvent, true);\r
+\r
+ // Create a new thread to wait for events\r
+ Debug.WriteLine("m_eventThread.Start()");\r
+ m_eventThread = new Thread(new ThreadStart(EventWait));\r
+ m_eventThread.Name = "Media Event Thread";\r
+ m_eventThread.Start();\r
+\r
+ m_Bitmap = Properties.Resources.lgs;\r
+\r
+ tcWorker = new BackgroundWorker();\r
+ tcWorker.DoWork += TcWorker_DoWork;\r
+ tcWorker.WorkerSupportsCancellation = true;\r
+ tcWorker.RunWorkerAsync(tcLock);\r
+\r
+ }\r
+ catch {\r
+ Dispose();\r
+ throw;\r
+ }\r
+ }\r
+\r
+ private void FillTheHunStringvalues() {\r
+ stateHunStringValues.Add(GraphState.Exiting, StringResource.KILEPES);\r
+ stateHunStringValues.Add(GraphState.Paused, StringResource.SZUNETELTETETT);\r
+ stateHunStringValues.Add(GraphState.Playing, StringResource.LEJATSZAS);\r
+ stateHunStringValues.Add(GraphState.Stopped, StringResource.MEGALLITVA);\r
+ stateHunStringValues.Add(GraphState.Completed, StringResource.VEGE);\r
+ }\r
+\r
+ private void TcWorker_DoWork(object sender, DoWorkEventArgs e) {\r
+ while (!e.Cancel) {\r
+ UpdateTC();\r
+ Thread.Sleep(10);\r
+ }\r
+ }\r
+\r
+\r
+ // start playing\r
+ public void Play() {\r
+ // If we aren't already playing (or shutting down)\r
+ if (State == GraphState.Completed)\r
+ Stop();\r
+ if (State == GraphState.Stopped || State == GraphState.Paused) {\r
+ int hr = m_mediaCtrl.Run();\r
+ DsError.ThrowExceptionForHR(hr);\r
+\r
+ State = GraphState.Playing;\r
+ }\r
+ }\r
+\r
+ // Pause the capture graph.\r
+ public void Pause() {\r
+ // If we are playing\r
+ if (State == GraphState.Playing) {\r
+ int hr = m_mediaCtrl.Pause();\r
+ DsError.ThrowExceptionForHR(hr);\r
+\r
+ State = GraphState.Paused;\r
+ Seek(CurrentTC.ZeroBasedFrames);\r
+ }\r
+ }\r
+\r
+ // Pause the capture graph.\r
+ public void Stop() {\r
+ // Can only Stop when playing or paused\r
+ if (State == GraphState.Playing || State == GraphState.Paused || State == GraphState.Completed) {\r
+ int hr = m_mediaCtrl.Stop();\r
+ DsError.ThrowExceptionForHR(hr);\r
+ State = GraphState.Stopped;\r
+ }\r
+ Rewind();\r
+ PlayEvent?.Invoke();\r
+ }\r
+\r
+ // Reset the clip back to the beginning\r
+ public void Rewind() {\r
+ Seek(0);\r
+ }\r
+\r
+ public void Seek(int value) {\r
+ double frameLength = (double)MEDIATIME_REFERENCE / MediaDescription.FrameRate;\r
+ long avgTimePerFrame = (long)Math.Ceiling(MEDIATIME_REFERENCE / MediaDescription.FrameRate);\r
+ long requestedPosition = (long)Math.Ceiling(value * frameLength);\r
+ int hr = m_mediaSeek.SetPositions(requestedPosition, AMSeekingSeekingFlags.AbsolutePositioning, null, AMSeekingSeekingFlags.NoPositioning);\r
+ DsError.ThrowExceptionForHR(hr);\r
+\r
+ long currentPosition;\r
+ hr = m_mediaSeek.GetCurrentPosition(out currentPosition);\r
+ DsError.ThrowExceptionForHR(hr);\r
+ bool corrected = false;\r
+ int reachedFrames = (int)Math.Abs((double)currentPosition / avgTimePerFrame);\r
+ if (reachedFrames != value) {\r
+ //NTSC-n nem megy a seek a kerekítési hibák miatt, mindíg ua. a frame jön ki \r
+ requestedPosition += (int)frameLength / 2;\r
+ hr = m_mediaSeek.SetPositions(requestedPosition, AMSeekingSeekingFlags.AbsolutePositioning, null, AMSeekingSeekingFlags.NoPositioning);\r
+ DsError.ThrowExceptionForHR(hr);\r
+ corrected = true;\r
+ }\r
+\r
+ Debug.WriteLine("Seeking requested frame {0} got frame {1}, media position {2}, frame length {3}, corrected {4}", value, reachedFrames, requestedPosition, avgTimePerFrame, corrected);\r
+ }\r
+\r
+ private void UpdateTC() {\r
+ if (m_mediaSeek == null)\r
+ return;\r
+ long currentPosition;\r
+ int hr = m_mediaSeek.GetCurrentPosition(out currentPosition);\r
+ DsError.ThrowExceptionForHR(hr);\r
+ int frames = ReferenceTimeToFrames(currentPosition);\r
+ if (CurrentTC.ZeroBasedFrames != frames) {\r
+ CurrentTC.Set(frames);\r
+ //Debug.WriteLine("Current frame is {0} ({1}), media position is {2}, AVG frame time is {3}", frames, CurrentTC.ToString(), currentPosition, AvgTimePerFrame);\r
+ }\r
+ PlayEvent?.Invoke();\r
+\r
+ }\r
+\r
+ private int ReferenceTimeToFrames(long refTime) {\r
+ long AvgTimePerFrame = (long)Math.Ceiling(MEDIATIME_REFERENCE / MediaDescription.FrameRate);\r
+ return (int)Math.Abs((double)refTime / AvgTimePerFrame);\r
+ }\r
+\r
+ private void SetupGraph() {\r
+ int hr;\r
+\r
+ try {\r
+ IsError = false;\r
+ m_FilterGraph = new FilterGraph() as IFilterGraph2;\r
+\r
+ IGraphBuilder graphBuilder = m_FilterGraph as IGraphBuilder;\r
+ m_mediaSeek = m_FilterGraph as IMediaSeeking;\r
+ m_mediaEvent = m_FilterGraph as IMediaEvent;\r
+ m_mediaCtrl = m_FilterGraph as IMediaControl;\r
+ m_videoWindow = m_FilterGraph as IVideoWindow;\r
+\r
+#if DEBUG\r
+ m_DsRot = new DsROTEntry(m_FilterGraph);\r
+#endif\r
+ logger.Debug("Add SourceFilter to graph");\r
+ IBaseFilter sourceFilter = null;\r
+ hr = m_FilterGraph.AddSourceFilter(MediaDescription.FileName, MediaDescription.FileName, out sourceFilter);\r
+ DsError.ThrowExceptionForHR(hr);\r
+\r
+ //Type typeFromClsid = Type.GetTypeFromCLSID(new Guid("CCE7BD95-3BC4-4cfb-9664-0BF83201BE09"));\r
+ //splitter = (IBaseFilter)Activator.CreateInstance(typeFromClsid);\r
+ //m_FilterGraph.AddFilter(splitter, "MXF Splitter");\r
+ //splitter = FilterGraphTools.AddFilterByName(graphBuilder, FilterCategory.LegacyAmFilterCategory, "Sony MXF Splitter");\r
+\r
+ logger.Debug("Add LAVSplitter to graph");\r
+ IBaseFilter splitter = LoadSplitter(graphBuilder);\r
+ if (splitter == null)\r
+ throw new Exception("No splitter!");\r
+\r
+ logger.Debug("Connect SourceFilter -> LAVSplitter");\r
+ FilterGraphTools.ConnectFilters(graphBuilder, sourceFilter, "Output", splitter, "Input", true);\r
+\r
+ IAMStreamSelect amStreamSelect = (IAMStreamSelect)splitter;\r
+ if (amStreamSelect != null) {\r
+ int count = 0;\r
+ amStreamSelect.Count(out count);\r
+ int audioCount = 0;\r
+ for (int i = 0; i < count; i++) {\r
+ AMMediaType ppmt;\r
+ AMStreamSelectInfoFlags pdwFlags;\r
+ int plcid;\r
+ int pdwGroup;\r
+ string ppszName;\r
+ object ppObject;\r
+ amStreamSelect.Info(i, out ppmt, out pdwFlags, out plcid, out pdwGroup, out ppszName, out ppObject, out ppUnk);\r
+\r
+ if (ppmt.majorType == MediaType.Audio) {\r
+ Debug.WriteLine("Found audio channel");\r
+ audioCount++;\r
+ }\r
+\r
+ DsUtils.FreeAMMediaType(ppmt);\r
+ //Marshal.FreeCoTaskMem(ppszName);\r
+ if (ppObject != null)\r
+ DsUtils.ReleaseComObject(ppUnk);\r
+\r
+ }\r
+ Debug.WriteLine("Audio count: " + audioCount);\r
+ }\r
+\r
+ logger.Debug("Add LAVVideo to graph");\r
+ IBaseFilter videoDecoder = LoadVideoDecoder(graphBuilder);\r
+\r
+ if (videoDecoder == null)\r
+ throw new Exception("No video decoder!");\r
+\r
+ logger.Debug("Connect LAVSplitter -> LAVVideo");\r
+ FilterGraphTools.ConnectFilters(graphBuilder, splitter, "Video", videoDecoder, "Input", true);\r
+\r
+ logger.Debug("Add SampleGrabber to graph");\r
+ IBaseFilter sampGrabber = (IBaseFilter)new SampleGrabber();\r
+ ISampleGrabber sampleGrabber = (ISampleGrabber)sampGrabber;\r
+ ConfigureSampleGrabber(sampleGrabber);\r
+\r
+ hr = m_FilterGraph.AddFilter(sampGrabber, "Sample Grabber");\r
+ DsError.ThrowExceptionForHR(hr);\r
+\r
+ logger.Debug("Connect LAVVideo -> SampleGrabber");\r
+ FilterGraphTools.ConnectFilters(graphBuilder, videoDecoder, "Output", sampGrabber, "Input", true);\r
+\r
+ AMMediaType media = new AMMediaType();\r
+ sampleGrabber.GetConnectedMediaType(media);\r
+ logger.Debug("SaveSizeInfo");\r
+ SaveSizeInfo(media);\r
+ DsUtils.FreeAMMediaType(media);\r
+\r
+ logger.Debug("Add VideoMixingRenderer9 to graph");\r
+ m_videoRenderer = (IBaseFilter)new VideoMixingRenderer9();\r
+ hr = m_FilterGraph.AddFilter(m_videoRenderer, "Video Mixing Renderer 9");\r
+ DsError.ThrowExceptionForHR(hr);\r
+\r
+\r
+ try {\r
+ //IPin pin = DsFindPin.ByName(sampGrabber, "Output");\r
+ //m_FilterGraph.RenderEx(pin, AMRenderExFlags.RenderToExistingRenderers, IntPtr.Zero);\r
+ //Marshal.ReleaseComObject(pin);\r
+ logger.Debug("Connect SampleGrabber -> VideoMixingRenderer9");\r
+ FilterGraphTools.ConnectFilters(graphBuilder, sampGrabber, "Output", m_videoRenderer, "VMR Input0", true);\r
+ }\r
+ catch (Exception e) {\r
+ logger.Error(e);\r
+ }\r
+\r
+ try {\r
+ if (DsFindPin.ByName(splitter, "Audio") != null) {\r
+ logger.Debug("Add LAVAudio to graph");\r
+ IBaseFilter audioDecoder = null;\r
+ audioDecoder = LoadAudioDecoder(graphBuilder);\r
+ if (audioDecoder == null)\r
+ throw new Exception("No audio decoder!");\r
+\r
+ logger.Debug("Connect LAVSplitter -> LAVAudio");\r
+ FilterGraphTools.ConnectFilters(graphBuilder, splitter, "Audio", audioDecoder, "Input", true);\r
+ FilterGraphTools.RenderPin(graphBuilder, audioDecoder, "Output");\r
+ } else {\r
+ logger.Warn("Audio pin not available");\r
+ }\r
+ }\r
+ catch (Exception ex) {\r
+ logger.Warn("Audio pin not available");\r
+ }\r
+\r
+\r
+ //logger.Debug("SaveSizeInfo");\r
+ //SaveSizeInfo(sampGrabber as ISampleGrabber);\r
+ logger.Debug("SetTimeCodes");\r
+ SetTimeCodes();\r
+ logger.Debug("ConfigureVideoWindow");\r
+ ConfigureVideoWindow();\r
+\r
+ logger.Debug("Enable YADIF deinterlace");\r
+ ILAVVideoSettings settings = (ILAVVideoSettings)videoDecoder;\r
+ settings.SetSWDeintMode(LAVSWDeintModes.SWDeintMode_YADIF);\r
+ settings.SetSWDeintOutput(LAVDeintOutput.DeintOutput_FramePer2Field);\r
+ }\r
+ catch (Exception e) {\r
+ Debug.WriteLine(e.Message);\r
+ IsError = true;\r
+ }\r
+ finally {\r
+ }\r
+#if DEBUG\r
+ // Double check to make sure we aren't releasing something\r
+ // important.\r
+ //GC.Collect();\r
+ //GC.WaitForPendingFinalizers();\r
+#endif\r
+ }\r
+\r
+ private static IBaseFilter LoadVideoDecoder(IGraphBuilder graphBuilder) {\r
+ IBaseFilter videoDecoder = null;\r
+ ILAVVideoSettings lavVideoSettings;\r
+ videoDecoder = FilterProvider.GetVideoFilter(out lavVideoSettings);\r
+ if (videoDecoder == null)\r
+ videoDecoder = FilterGraphTools.AddFilterByName(graphBuilder, FilterCategory.LegacyAmFilterCategory, "LAV Video Decoder");\r
+ else\r
+ graphBuilder.AddFilter(videoDecoder, "LAV Video Decoder");\r
+ return videoDecoder;\r
+ }\r
+\r
+ private static IBaseFilter LoadAudioDecoder(IGraphBuilder graphBuilder) {\r
+ IBaseFilter audioDecoder = null;\r
+ ILAVAudioSettings lavAudioSettings;\r
+ ILAVAudioStatus lavAudioStatus;\r
+ audioDecoder = FilterProvider.GetAudioFilter(out lavAudioSettings, out lavAudioStatus);\r
+ if (audioDecoder == null)\r
+ audioDecoder = FilterGraphTools.AddFilterByName(graphBuilder, FilterCategory.LegacyAmFilterCategory, "LAV Audio Decoder");\r
+ else\r
+ graphBuilder.AddFilter(audioDecoder, "LAV Audio Decoder");\r
+ return audioDecoder;\r
+ }\r
+\r
+ private static IBaseFilter LoadSplitter(IGraphBuilder graphBuilder) {\r
+ IBaseFilter splitter = null;\r
+ ILAVSplitterSettings lavSplitterSettings;\r
+ splitter = FilterProvider.GetSplitter(out lavSplitterSettings);\r
+ if (splitter == null)\r
+ splitter = FilterGraphTools.AddFilterByName(graphBuilder, FilterCategory.LegacyAmFilterCategory, "LAV Splitter");\r
+ else\r
+ graphBuilder.AddFilter(splitter, "LAV Splitter");\r
+ return splitter;\r
+ }\r
+\r
+ private void SetTimeCodes() {\r
+ int hr;\r
+ long duration;\r
+ hr = m_mediaSeek.GetDuration(out duration);\r
+ DsError.ThrowExceptionForHR(hr);\r
+ MediaDescription.duration = new Timecode();\r
+ MediaDescription.Duration.Set(ReferenceTimeToFrames(duration));\r
+ if (MediaDescription.FirstFrame == null) {\r
+ try {\r
+ MXFFile mxf = new MXFFile(MediaDescription.FileName);\r
+ mxf.Inspect();\r
+ //MediaDescription.firstFrame = new Timecode(mxf.FirstSystemItem?.UserDateFullFrameNb, MediaDescription.FrameRate);\r
+ MediaDescription.firstFrame = new Timecode((int)mxf.TimecodeComponent.StartTimecode, (float)mxf.TimecodeComponent.RoundedTimecodeBase);\r
+ }\r
+ catch (Exception ex) {\r
+ MediaDescription.firstFrame = new Timecode();\r
+ }\r
+ }\r
+ //MediaDescription.firstFrame = new Timecode();\r
+ CurrentTC = new Timecode(MediaDescription.FirstFrame);\r
+ }\r
+\r
+\r
+ // Configure the video window\r
+ private void ConfigureVideoWindow() {\r
+ int hr;\r
+\r
+ // Set the output window\r
+ hr = m_videoWindow.put_Owner(playerWindow.Handle);\r
+ DsError.ThrowExceptionForHR(hr);\r
+\r
+ hr = m_videoWindow.put_MessageDrain(playerWindow.Handle);\r
+ DsError.ThrowExceptionForHR(hr);\r
+\r
+ // Set the window style\r
+ hr = m_videoWindow.put_WindowStyle((WindowStyle.Child | WindowStyle.ClipChildren | WindowStyle.ClipSiblings));\r
+ DsError.ThrowExceptionForHR(hr);\r
+\r
+ // Make the window visible\r
+ hr = m_videoWindow.put_Visible(OABool.True);\r
+ DsError.ThrowExceptionForHR(hr);\r
+\r
+ UpdateVideoWindow();\r
+ }\r
+\r
+ public void UpdateVideoWindow() {\r
+ Size resolution = MediaDescription.Resolution;\r
+ if (resolution.Width == 0 || resolution.Height == 0)\r
+ return;\r
+ int hr;\r
+ // Position the playing location\r
+ Rectangle rc = playerWindow.ClientRectangle;\r
+ double x = (double)resolution.Width / resolution.Height;\r
+ double y = (double)rc.Right / rc.Bottom;\r
+ int playerWidth = 0;\r
+ int playerHeight = 0;\r
+ if (x - y < 0) {\r
+ playerWidth = (int)Math.Ceiling(rc.Bottom * x);\r
+ playerHeight = rc.Bottom;\r
+ } else {\r
+ x = (double)resolution.Height / resolution.Width;\r
+ playerWidth = rc.Right;\r
+ playerHeight = (int)Math.Ceiling(rc.Right * x); ;\r
+ }\r
+\r
+ hr = m_videoWindow.SetWindowPosition((rc.Right - playerWidth) / 2, (rc.Bottom - playerHeight) / 2, playerWidth, playerHeight);\r
+ DsError.ThrowExceptionForHR(hr);\r
+ }\r
+\r
+ public void ToggleFullscreen() {\r
+ m_videoWindow.put_FullScreenMode(IsFullscreen() ? OABool.False : OABool.True);\r
+ }\r
+\r
+ public bool IsFullscreen() {\r
+ OABool isFullscreen;\r
+ int hr = m_videoWindow.get_FullScreenMode(out isFullscreen);\r
+ DsError.ThrowExceptionForHR(hr);\r
+ return isFullscreen == OABool.True ? true : false;\r
+ }\r
+\r
+ // Set the options on the sample grabber\r
+ private void ConfigureSampleGrabber(ISampleGrabber sampGrabber) {\r
+ int hr;\r
+ //AMMediaType media;\r
+ //media = new AMMediaType();\r
+ //media.majorType = MediaType.Video;\r
+ //media.subType = MediaSubType.RGB24;\r
+ //media.formatType = FormatType.VideoInfo;\r
+ //hr = sampGrabber.SetMediaType(media);\r
+ //DsError.ThrowExceptionForHR(hr);\r
+ //DsUtils.FreeAMMediaType(media);\r
+\r
+ hr = sampGrabber.SetCallback(this, 1);\r
+ DsError.ThrowExceptionForHR(hr);\r
+\r
+ // Configure the samplegrabber\r
+ hr = sampGrabber.SetBufferSamples(true);\r
+ DsError.ThrowExceptionForHR(hr);\r
+ }\r
+\r
+ private void SaveSizeInfo(AMMediaType media) {\r
+ //int hr;\r
+ //AMMediaType media = new AMMediaType();\r
+ //hr = sampGrabber.GetConnectedMediaType(media);\r
+ //DsError.ThrowExceptionForHR(hr);\r
+\r
+ if ((media.formatType != FormatType.VideoInfo) || (media.formatPtr == IntPtr.Zero)) {\r
+ throw new NotSupportedException("Unknown Grabber Media Format");\r
+ }\r
+\r
+ // Grab the size info\r
+ VideoInfoHeader videoInfoHeader = (VideoInfoHeader)Marshal.PtrToStructure(media.formatPtr, typeof(VideoInfoHeader));\r
+ MediaDescription.resolution = new Size(videoInfoHeader.BmiHeader.Width, videoInfoHeader.BmiHeader.Height);\r
+ MediaDescription.frameRate = MEDIATIME_REFERENCE / videoInfoHeader.AvgTimePerFrame;\r
+\r
+ m_stride = videoInfoHeader.BmiHeader.Width * (videoInfoHeader.BmiHeader.BitCount / 8);\r
+ }\r
+\r
+ // Shut down capture\r
+ private void CloseInterfaces() {\r
+ Debug.WriteLine("CloseInterfaces");\r
+ int hr;\r
+ GC.SuppressFinalize(this);\r
+ if (tcWorker != null)\r
+ tcWorker.CancelAsync();\r
+ lock (this) {\r
+ if (State != GraphState.Exiting) {\r
+ State = GraphState.Exiting;\r
+\r
+ // Release the thread (if the thread was started)\r
+ if (m_mre != null) {\r
+ m_mre.Set();\r
+ }\r
+ }\r
+\r
+ if (m_mediaCtrl != null) {\r
+ // Stop the graph\r
+ hr = m_mediaCtrl.Stop();\r
+ FilterGraphTools.DisconnectAllPins((IGraphBuilder)m_mediaCtrl);\r
+ FilterGraphTools.RemoveAllFilters((IGraphBuilder)m_mediaCtrl);\r
+ m_mediaCtrl = null;\r
+\r
+ }\r
+\r
+ if (m_videoWindow != null) {\r
+ hr = m_videoWindow.put_Visible(OABool.False);\r
+ hr = m_videoWindow.put_MessageDrain(IntPtr.Zero);\r
+ hr = m_videoWindow.put_Owner(IntPtr.Zero);\r
+ m_videoWindow = null;\r
+ }\r
+\r
+ m_mediaEvent = null;\r
+ m_mediaSeek = null;\r
+\r
+#if DEBUG\r
+ if (m_DsRot != null) {\r
+ m_DsRot.Dispose();\r
+ m_DsRot = null;\r
+ }\r
+#endif\r
+ if (m_FilterGraph != null) {\r
+ Marshal.ReleaseComObject(m_FilterGraph);\r
+ m_FilterGraph = null;\r
+ }\r
+ }\r
+ GC.Collect();\r
+ //if (m_eventThread != null)\r
+ // m_eventThread.Join();\r
+ }\r
+\r
+ public int SampleCB(double SampleTime, IMediaSample pSample) {\r
+ Marshal.ReleaseComObject(pSample);\r
+ return 0;\r
+ }\r
+\r
+ public int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen) {\r
+ return 0;\r
+ int frames = (int)Math.Abs(SampleTime * MediaDescription.FrameRate);\r
+ //Debug.WriteLine("BufferCB frames {0}, sample time {1}", frames, SampleTime);\r
+ Font font = new Font("Tahoma", 30);\r
+ string display = frames.ToString();\r
+ SizeF size = new SizeF(100, 100);\r
+ m_Bitmap = new Bitmap((int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height));\r
+ GraphicsUnit units = GraphicsUnit.Point;\r
+ RectangleF bitmapRectF = m_Bitmap.GetBounds(ref units);\r
+\r
+ Graphics g = Graphics.FromImage(m_Bitmap);\r
+\r
+ g.SmoothingMode = SmoothingMode.AntiAlias;\r
+ g.InterpolationMode = InterpolationMode.HighQualityBicubic;\r
+ g.PixelOffsetMode = PixelOffsetMode.HighQuality;\r
+ g.FillRectangle(Brushes.Transparent, bitmapRectF);\r
+ g.DrawString(display, font, Brushes.White, bitmapRectF);\r
+ g.Flush();\r
+\r
+ m_Bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);\r
+ Rectangle r = new Rectangle(0, 0, m_Bitmap.Width, m_Bitmap.Height);\r
+ lock (this) {\r
+ BitmapData bmdLogo = m_Bitmap.LockBits(r, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);\r
+ if (bmdLogo != null) {\r
+ IntPtr ipSource = bmdLogo.Scan0;\r
+ IntPtr ipDest = pBuffer;\r
+\r
+ for (int x = 0; x < bmdLogo.Height; x++) {\r
+ CopyMemory(ipDest, ipSource, (uint)bmdLogo.Stride);\r
+ ipDest = (IntPtr)(ipDest.ToInt64() + m_stride);\r
+ ipSource = (IntPtr)(ipSource.ToInt64() + bmdLogo.Stride);\r
+ }\r
+ }\r
+ m_Bitmap.UnlockBits(bmdLogo);\r
+ bmdLogo = null;\r
+ }\r
+ return 0;\r
+ }\r
+\r
+ // Wait for events to happen. This approach uses waiting on an event handle.\r
+ // The nice thing about doing it this way is that you aren't in the windows message\r
+ // loop, and don't have to worry about re-entrency or taking too long. Plus, being\r
+ // in a class as we are, we don't have access to the message loop.\r
+ // Alternately, you can receive your events as windows messages. See\r
+ // IMediaEventEx.SetNotifyWindow.\r
+ private void EventWait() {\r
+ // Returned when GetEvent is called but there are no events\r
+ const int E_ABORT = unchecked((int)0x80004004);\r
+\r
+ int hr;\r
+ IntPtr p1, p2;\r
+ EventCode ec;\r
+\r
+ do {\r
+ // Wait for an event\r
+ m_mre.WaitOne(-1, true);\r
+\r
+ // Avoid contention for m_State\r
+ lock (this) {\r
+ // If we are not shutting down\r
+ if (State != GraphState.Exiting) {\r
+ // Read the event\r
+ for (\r
+ hr = m_mediaEvent.GetEvent(out ec, out p1, out p2, 0);\r
+ hr >= 0;\r
+ hr = m_mediaEvent.GetEvent(out ec, out p1, out p2, 0)\r
+ ) {\r
+ // Write the event name to the debug window\r
+ Debug.WriteLine(ec.ToString());\r
+\r
+ // If the clip is finished playing\r
+ if (ec == EventCode.Complete) {\r
+ State = GraphState.Completed;\r
+ }\r
+\r
+ // Release any resources the message allocated\r
+ hr = m_mediaEvent.FreeEventParams(ec, p1, p2);\r
+ DsError.ThrowExceptionForHR(hr);\r
+\r
+ //lock (tcLock) {\r
+ // UpdateTC("");\r
+ //}\r
+\r
+ }\r
+\r
+ // If the error that exited the loop wasn't due to running out of events\r
+ if (hr != E_ABORT) {\r
+ DsError.ThrowExceptionForHR(hr);\r
+ }\r
+ } else {\r
+ // We are shutting down\r
+ Debug.WriteLine("Shutdown");\r
+ break;\r
+ }\r
+ }\r
+ } while (true);\r
+ }\r
+\r
+ }\r
+}\r
using System.Threading;\r
\r
using DirectShowLib;\r
-using DirectShowLib.Utils;\r
using Microsoft.Win32.SafeHandles;\r
using System.ComponentModel;\r
using System.Drawing.Imaging;\r
}\r
\r
public Dictionary<GraphState, string> stateHunStringValues = new Dictionary<GraphState, string>();\r
-\r
public MediaDescription MediaDescription { get; internal set; }\r
public Timecode CurrentTC { get; internal set; }\r
public GraphState State { get; internal set; }\r
-\r
- private IFilterGraph2 m_FilterGraph;\r
- private IMediaControl m_mediaCtrl;\r
- private IMediaEvent m_mediaEvent;\r
-\r
- // Event used by Media Event thread\r
private ManualResetEvent m_mre;\r
private BackgroundWorker tcWorker;\r
- // Current state of the graph (can change async)\r
-\r
public event DxPlayEvent PlayEvent;\r
public delegate void DxPlayEvent();\r
-\r
private Thread m_eventThread = null;\r
- private IMediaSeeking m_mediaSeek = null;\r
- private IMediaPosition m_mediaPosition = null;\r
-\r
- private IVideoWindow m_videoWindow = null;\r
- private IBaseFilter m_videoRenderer = null;\r
private object tcLock = new object();\r
Bitmap m_Bitmap = null;\r
public bool IsError { get; set; }\r
-#if DEBUG\r
- // Allow you to "Connect to remote graph" from GraphEdit\r
- DsROTEntry m_DsRot;\r
-#endif\r
private int m_stride;\r
\r
- // Release everything.\r
public void Dispose() {\r
CloseInterfaces();\r
}\r
\r
Control playerWindow;\r
private object ppUnk;\r
+ private PlayerGraph graph;\r
\r
// Play an avi file into a window. Allow for snapshots.\r
// (Control to show video in, Avi file to play\r
// Get the event handle the graph will use to signal\r
// when events occur\r
Debug.WriteLine("GetEventHandle");\r
- hr = m_mediaEvent.GetEventHandle(out hEvent);\r
+ hr = graph.MediaEvent.GetEventHandle(out hEvent);\r
DsError.ThrowExceptionForHR(hr);\r
\r
// Wrap the graph event with a ManualResetEvent\r
}\r
}\r
\r
+ private void SetupGraph() {\r
+ graph = new PlayerGraph(MediaDescription.FileName);\r
+\r
+ AMMediaType media = new AMMediaType();\r
+ graph.SampleGrabber.GetConnectedMediaType(media);\r
+ logger.Debug("SaveSizeInfo");\r
+ SaveSizeInfo(media);\r
+ DsUtils.FreeAMMediaType(media);\r
+\r
+ logger.Debug("ConfigureSampleGrabber");\r
+ ConfigureSampleGrabber(graph.SampleGrabber);\r
+ logger.Debug("SetTimeCodes");\r
+ SetTimeCodes();\r
+ logger.Debug("ConfigureVideoWindow");\r
+ ConfigureVideoWindow();\r
+ }\r
+\r
private void FillTheHunStringvalues() {\r
stateHunStringValues.Add(GraphState.Exiting, StringResource.KILEPES);\r
stateHunStringValues.Add(GraphState.Paused, StringResource.SZUNETELTETETT);\r
if (State == GraphState.Completed)\r
Stop();\r
if (State == GraphState.Stopped || State == GraphState.Paused) {\r
- int hr = m_mediaCtrl.Run();\r
+ int hr = graph.MediaControl.Run();\r
DsError.ThrowExceptionForHR(hr);\r
\r
State = GraphState.Playing;\r
public void Pause() {\r
// If we are playing\r
if (State == GraphState.Playing) {\r
- int hr = m_mediaCtrl.Pause();\r
+ int hr = graph.MediaControl.Pause();\r
DsError.ThrowExceptionForHR(hr);\r
\r
State = GraphState.Paused;\r
public void Stop() {\r
// Can only Stop when playing or paused\r
if (State == GraphState.Playing || State == GraphState.Paused || State == GraphState.Completed) {\r
- int hr = m_mediaCtrl.Stop();\r
+ int hr = graph.MediaControl.Stop();\r
DsError.ThrowExceptionForHR(hr);\r
State = GraphState.Stopped;\r
}\r
}\r
\r
public void Seek(int value) {\r
+ if (graph == null || graph.MediaSeeking == null)\r
+ return;\r
+\r
double frameLength = (double)MEDIATIME_REFERENCE / MediaDescription.FrameRate;\r
long avgTimePerFrame = (long)Math.Ceiling(MEDIATIME_REFERENCE / MediaDescription.FrameRate);\r
long requestedPosition = (long)Math.Ceiling(value * frameLength);\r
- int hr = m_mediaSeek.SetPositions(requestedPosition, AMSeekingSeekingFlags.AbsolutePositioning, null, AMSeekingSeekingFlags.NoPositioning);\r
+ int hr = graph.MediaSeeking.SetPositions(requestedPosition, AMSeekingSeekingFlags.AbsolutePositioning, null, AMSeekingSeekingFlags.NoPositioning);\r
DsError.ThrowExceptionForHR(hr);\r
\r
long currentPosition;\r
- hr = m_mediaSeek.GetCurrentPosition(out currentPosition);\r
+ hr = graph.MediaSeeking.GetCurrentPosition(out currentPosition);\r
DsError.ThrowExceptionForHR(hr);\r
bool corrected = false;\r
int reachedFrames = (int)Math.Abs((double)currentPosition / avgTimePerFrame);\r
if (reachedFrames != value) {\r
//NTSC-n nem megy a seek a kerekítési hibák miatt, mindíg ua. a frame jön ki \r
requestedPosition += (int)frameLength / 2;\r
- hr = m_mediaSeek.SetPositions(requestedPosition, AMSeekingSeekingFlags.AbsolutePositioning, null, AMSeekingSeekingFlags.NoPositioning);\r
+ hr = graph.MediaSeeking.SetPositions(requestedPosition, AMSeekingSeekingFlags.AbsolutePositioning, null, AMSeekingSeekingFlags.NoPositioning);\r
DsError.ThrowExceptionForHR(hr);\r
corrected = true;\r
}\r
}\r
\r
private void UpdateTC() {\r
- if (m_mediaSeek == null)\r
+ if (graph == null || graph.MediaSeeking == null)\r
return;\r
long currentPosition;\r
- int hr = m_mediaSeek.GetCurrentPosition(out currentPosition);\r
+ int hr = graph.MediaSeeking.GetCurrentPosition(out currentPosition);\r
DsError.ThrowExceptionForHR(hr);\r
int frames = ReferenceTimeToFrames(currentPosition);\r
if (CurrentTC.ZeroBasedFrames != frames) {\r
return (int)Math.Abs((double)refTime / AvgTimePerFrame);\r
}\r
\r
- private void SetupGraph() {\r
- int hr;\r
-\r
- try {\r
- IsError = false;\r
- m_FilterGraph = new FilterGraph() as IFilterGraph2;\r
-\r
- IGraphBuilder graphBuilder = m_FilterGraph as IGraphBuilder;\r
- m_mediaSeek = m_FilterGraph as IMediaSeeking;\r
- m_mediaPosition = m_FilterGraph as IMediaPosition;\r
- m_mediaEvent = m_FilterGraph as IMediaEvent;\r
- m_mediaCtrl = m_FilterGraph as IMediaControl;\r
- m_videoWindow = m_FilterGraph as IVideoWindow;\r
-\r
-#if DEBUG\r
- m_DsRot = new DsROTEntry(m_FilterGraph);\r
-#endif\r
- logger.Debug("Add SourceFilter to graph");\r
- IBaseFilter sourceFilter = null;\r
- hr = m_FilterGraph.AddSourceFilter(MediaDescription.FileName, MediaDescription.FileName, out sourceFilter);\r
- DsError.ThrowExceptionForHR(hr);\r
-\r
- //Type typeFromClsid = Type.GetTypeFromCLSID(new Guid("CCE7BD95-3BC4-4cfb-9664-0BF83201BE09"));\r
- //splitter = (IBaseFilter)Activator.CreateInstance(typeFromClsid);\r
- //m_FilterGraph.AddFilter(splitter, "MXF Splitter");\r
- //splitter = FilterGraphTools.AddFilterByName(graphBuilder, FilterCategory.LegacyAmFilterCategory, "Sony MXF Splitter");\r
-\r
- logger.Debug("Add LAVSplitter to graph");\r
- IBaseFilter splitter = LoadSplitter(graphBuilder);\r
- if (splitter == null)\r
- throw new Exception("No splitter!");\r
-\r
- logger.Debug("Connect SourceFilter -> LAVSplitter");\r
- FilterGraphTools.ConnectFilters(graphBuilder, sourceFilter, "Output", splitter, "Input", true);\r
-\r
- //IAMStreamSelect amStreamSelect = (IAMStreamSelect)splitter;\r
- //if (amStreamSelect != null) {\r
- // int count = 0;\r
- // amStreamSelect.Count(out count);\r
- // int audioCount = 0;\r
- // for (int i = 0; i < count; i++) {\r
- // AMMediaType ppmt;\r
- // AMStreamSelectInfoFlags pdwFlags;\r
- // int plcid;\r
- // int pdwGroup;\r
- // string ppszName;\r
- // object ppObject;\r
- // amStreamSelect.Info(i, out ppmt, out pdwFlags, out plcid, out pdwGroup, out ppszName, out ppObject, out ppUnk);\r
-\r
- // if (ppmt.majorType == MediaType.Audio) {\r
- // Debug.WriteLine("Found audio channel");\r
- // audioCount++;\r
- // }\r
-\r
- // DsUtils.FreeAMMediaType(ppmt);\r
- // //Marshal.FreeCoTaskMem(ppszName);\r
- // if (ppObject != null)\r
- // DsUtils.ReleaseComObject(ppUnk);\r
-\r
- // }\r
- // Debug.WriteLine("Audio count: " + audioCount);\r
- //}\r
-\r
- logger.Debug("Add LAVVideo to graph");\r
- IBaseFilter videoDecoder = LoadVideoDecoder(graphBuilder);\r
-\r
- if (videoDecoder == null)\r
- throw new Exception("No video decoder!");\r
-\r
- logger.Debug("Connect LAVSplitter -> LAVVideo");\r
- FilterGraphTools.ConnectFilters(graphBuilder, splitter, "Video", videoDecoder, "Input", true);\r
-\r
- logger.Debug("Add SampleGrabber to graph");\r
- IBaseFilter sampGrabber = (IBaseFilter)new SampleGrabber();\r
- ConfigureSampleGrabber((ISampleGrabber)sampGrabber);\r
- hr = m_FilterGraph.AddFilter(sampGrabber, "Sample Grabber");\r
- DsError.ThrowExceptionForHR(hr);\r
-\r
- logger.Debug("Connect LAVVideo -> SampleGrabber");\r
- FilterGraphTools.ConnectFilters(graphBuilder, videoDecoder, "Output", sampGrabber, "Input", true);\r
-\r
- logger.Debug("Add VideoMixingRenderer9 to graph");\r
- m_videoRenderer = (IBaseFilter)new VideoMixingRenderer9();\r
- hr = m_FilterGraph.AddFilter(m_videoRenderer, "Video Mixing Renderer 9");\r
- DsError.ThrowExceptionForHR(hr);\r
-\r
- //logger.Debug("Add VideoMixingRenderer9 to graph");\r
- //IVMRDeinterlaceControl9 deinterlace = (IVMRDeinterlaceControl9)m_videoRenderer;\r
- //Guid interlaceMode;\r
- //deinterlace.GetActualDeinterlaceMode(0, out interlaceMode);\r
-\r
- try {\r
- logger.Debug("Connect SampleGrabber -> VideoMixingRenderer9");\r
- FilterGraphTools.ConnectFilters(graphBuilder, sampGrabber, "Output", m_videoRenderer, "VMR Input0", true);\r
- }\r
- catch (Exception e) {\r
- logger.Error(e);\r
- }\r
-\r
- try {\r
- if (DsFindPin.ByName(splitter, "Audio") != null) {\r
- logger.Debug("Add LAVAudio to graph");\r
- IBaseFilter audioDecoder = null;\r
- audioDecoder = LoadAudioDecoder(graphBuilder);\r
- if (audioDecoder == null)\r
- throw new Exception("No audio decoder!");\r
-\r
- logger.Debug("Connect LAVSplitter -> LAVAudio");\r
- FilterGraphTools.ConnectFilters(graphBuilder, splitter, "Audio", audioDecoder, "Input", true);\r
- FilterGraphTools.RenderPin(graphBuilder, audioDecoder, "Output");\r
- } else {\r
- logger.Warn("Audio pin not available");\r
- }\r
- }\r
- catch (Exception ex) {\r
- logger.Warn("Audio pin not available");\r
- }\r
-\r
- logger.Debug("SaveSizeInfo");\r
- SaveSizeInfo(sampGrabber as ISampleGrabber);\r
- logger.Debug("SetTimeCodes");\r
- SetTimeCodes();\r
- logger.Debug("ConfigureVideoWindow");\r
- ConfigureVideoWindow();\r
-\r
- logger.Debug("Enable YADIF deinterlace");\r
- ILAVVideoSettings settings = (ILAVVideoSettings)videoDecoder;\r
- //settings.SetSWDeintMode(LAVSWDeintModes.SWDeintMode_None);\r
- settings.SetSWDeintMode(LAVSWDeintModes.SWDeintMode_YADIF);\r
- settings.SetSWDeintOutput(LAVDeintOutput.DeintOutput_FramePer2Field);\r
- }\r
- catch (Exception e) {\r
- Debug.WriteLine(e.Message);\r
- IsError = true;\r
- }\r
- finally {\r
- }\r
-#if DEBUG\r
- // Double check to make sure we aren't releasing something\r
- // important.\r
- //GC.Collect();\r
- //GC.WaitForPendingFinalizers();\r
-#endif\r
- }\r
-\r
- private static IBaseFilter LoadVideoDecoder(IGraphBuilder graphBuilder) {\r
- IBaseFilter videoDecoder = null;\r
- ILAVVideoSettings lavVideoSettings;\r
- videoDecoder = FilterProvider.GetVideoFilter(out lavVideoSettings);\r
- if (videoDecoder == null)\r
- videoDecoder = FilterGraphTools.AddFilterByName(graphBuilder, FilterCategory.LegacyAmFilterCategory, "LAV Video Decoder");\r
- else\r
- graphBuilder.AddFilter(videoDecoder, "LAV Video Decoder");\r
- return videoDecoder;\r
- }\r
-\r
- private static IBaseFilter LoadAudioDecoder(IGraphBuilder graphBuilder) {\r
- IBaseFilter audioDecoder = null;\r
- ILAVAudioSettings lavAudioSettings;\r
- ILAVAudioStatus lavAudioStatus;\r
- audioDecoder = FilterProvider.GetAudioFilter(out lavAudioSettings, out lavAudioStatus);\r
- if (audioDecoder == null)\r
- audioDecoder = FilterGraphTools.AddFilterByName(graphBuilder, FilterCategory.LegacyAmFilterCategory, "LAV Audio Decoder");\r
- else\r
- graphBuilder.AddFilter(audioDecoder, "LAV Audio Decoder");\r
- return audioDecoder;\r
- }\r
-\r
- private static IBaseFilter LoadSplitter(IGraphBuilder graphBuilder) {\r
- IBaseFilter splitter = null;\r
- ILAVSplitterSettings lavSplitterSettings;\r
- splitter = FilterProvider.GetSplitter(out lavSplitterSettings);\r
- if (splitter == null)\r
- splitter = FilterGraphTools.AddFilterByName(graphBuilder, FilterCategory.LegacyAmFilterCategory, "LAV Splitter");\r
- else\r
- graphBuilder.AddFilter(splitter, "LAV Splitter");\r
- return splitter;\r
- }\r
-\r
private void SetTimeCodes() {\r
int hr;\r
long duration;\r
- hr = m_mediaSeek.GetDuration(out duration);\r
+ hr = graph.MediaSeeking.GetDuration(out duration);\r
DsError.ThrowExceptionForHR(hr);\r
MediaDescription.duration = new Timecode();\r
MediaDescription.Duration.Set(ReferenceTimeToFrames(duration));\r
int hr;\r
\r
// Set the output window\r
- hr = m_videoWindow.put_Owner(playerWindow.Handle);\r
+ hr = graph.VideoWindow.put_Owner(playerWindow.Handle);\r
DsError.ThrowExceptionForHR(hr);\r
\r
- hr = m_videoWindow.put_MessageDrain(playerWindow.Handle);\r
+ hr = graph.VideoWindow.put_MessageDrain(playerWindow.Handle);\r
DsError.ThrowExceptionForHR(hr);\r
\r
// Set the window style\r
- hr = m_videoWindow.put_WindowStyle((WindowStyle.Child | WindowStyle.ClipChildren | WindowStyle.ClipSiblings));\r
+ hr = graph.VideoWindow.put_WindowStyle((WindowStyle.Child | WindowStyle.ClipChildren | WindowStyle.ClipSiblings));\r
DsError.ThrowExceptionForHR(hr);\r
\r
// Make the window visible\r
- hr = m_videoWindow.put_Visible(OABool.True);\r
+ hr = graph.VideoWindow.put_Visible(OABool.True);\r
DsError.ThrowExceptionForHR(hr);\r
\r
UpdateVideoWindow();\r
playerHeight = (int)Math.Ceiling(rc.Right * x); ;\r
}\r
\r
- hr = m_videoWindow.SetWindowPosition((rc.Right - playerWidth) / 2, (rc.Bottom - playerHeight) / 2, playerWidth, playerHeight);\r
+ hr = graph.VideoWindow.SetWindowPosition((rc.Right - playerWidth) / 2, (rc.Bottom - playerHeight) / 2, playerWidth, playerHeight);\r
DsError.ThrowExceptionForHR(hr);\r
}\r
\r
public void ToggleFullscreen() {\r
- m_videoWindow.put_FullScreenMode(IsFullscreen() ? OABool.False : OABool.True);\r
+ graph.VideoWindow.put_FullScreenMode(IsFullscreen() ? OABool.False : OABool.True);\r
}\r
\r
public bool IsFullscreen() {\r
OABool isFullscreen;\r
- int hr = m_videoWindow.get_FullScreenMode(out isFullscreen);\r
+ int hr = graph.VideoWindow.get_FullScreenMode(out isFullscreen);\r
DsError.ThrowExceptionForHR(hr);\r
return isFullscreen == OABool.True ? true : false;\r
}\r
\r
// Set the options on the sample grabber\r
private void ConfigureSampleGrabber(ISampleGrabber sampGrabber) {\r
- AMMediaType media;\r
int hr;\r
-\r
- // Set the media type to Video/RBG24\r
- media = new AMMediaType();\r
- media.majorType = MediaType.Video;\r
- media.subType = MediaSubType.RGB24;\r
- media.formatType = FormatType.VideoInfo;\r
- hr = sampGrabber.SetMediaType(media);\r
- DsError.ThrowExceptionForHR(hr);\r
-\r
- DsUtils.FreeAMMediaType(media);\r
- media = null;\r
+ //AMMediaType media;\r
+ //media = new AMMediaType();\r
+ //media.majorType = MediaType.Video;\r
+ //media.subType = MediaSubType.RGB24;\r
+ //media.formatType = FormatType.VideoInfo;\r
+ //hr = sampGrabber.SetMediaType(media);\r
+ //DsError.ThrowExceptionForHR(hr);\r
+ //DsUtils.FreeAMMediaType(media);\r
\r
hr = sampGrabber.SetCallback(this, 1);\r
DsError.ThrowExceptionForHR(hr);\r
DsError.ThrowExceptionForHR(hr);\r
}\r
\r
- private void SaveSizeInfo(ISampleGrabber sampGrabber) {\r
- int hr;\r
-\r
- // Get the media type from the SampleGrabber\r
- AMMediaType media = new AMMediaType();\r
- hr = sampGrabber.GetConnectedMediaType(media);\r
- DsError.ThrowExceptionForHR(hr);\r
+ private void SaveSizeInfo(AMMediaType media) {\r
+ //int hr;\r
+ //AMMediaType media = new AMMediaType();\r
+ //hr = sampGrabber.GetConnectedMediaType(media);\r
+ //DsError.ThrowExceptionForHR(hr);\r
\r
if ((media.formatType != FormatType.VideoInfo) || (media.formatPtr == IntPtr.Zero)) {\r
throw new NotSupportedException("Unknown Grabber Media Format");\r
MediaDescription.frameRate = MEDIATIME_REFERENCE / videoInfoHeader.AvgTimePerFrame;\r
\r
m_stride = videoInfoHeader.BmiHeader.Width * (videoInfoHeader.BmiHeader.BitCount / 8);\r
- DsUtils.FreeAMMediaType(media);\r
- media = null;\r
}\r
\r
// Shut down capture\r
private void CloseInterfaces() {\r
Debug.WriteLine("CloseInterfaces");\r
- int hr;\r
GC.SuppressFinalize(this);\r
if (tcWorker != null)\r
tcWorker.CancelAsync();\r
}\r
}\r
\r
- if (m_mediaCtrl != null) {\r
- // Stop the graph\r
- hr = m_mediaCtrl.Stop();\r
- FilterGraphTools.DisconnectAllPins((IGraphBuilder)m_mediaCtrl);\r
- FilterGraphTools.RemoveAllFilters((IGraphBuilder)m_mediaCtrl);\r
- m_mediaCtrl = null;\r
-\r
- }\r
-\r
- if (m_videoWindow != null) {\r
- hr = m_videoWindow.put_Visible(OABool.False);\r
- hr = m_videoWindow.put_MessageDrain(IntPtr.Zero);\r
- hr = m_videoWindow.put_Owner(IntPtr.Zero);\r
- m_videoWindow = null;\r
- }\r
-\r
- m_mediaEvent = null;\r
- m_mediaSeek = null;\r
- m_mediaPosition = null;\r
-\r
-#if DEBUG\r
- if (m_DsRot != null) {\r
- m_DsRot.Dispose();\r
- m_DsRot = null;\r
- }\r
-#endif\r
- if (m_FilterGraph != null) {\r
- Marshal.ReleaseComObject(m_FilterGraph);\r
- m_FilterGraph = null;\r
- }\r
+ if (graph != null)\r
+ graph.Dispose();\r
}\r
GC.Collect();\r
//if (m_eventThread != null)\r
if (State != GraphState.Exiting) {\r
// Read the event\r
for (\r
- hr = m_mediaEvent.GetEvent(out ec, out p1, out p2, 0);\r
+ hr = graph.MediaEvent.GetEvent(out ec, out p1, out p2, 0);\r
hr >= 0;\r
- hr = m_mediaEvent.GetEvent(out ec, out p1, out p2, 0)\r
+ hr = graph.MediaEvent.GetEvent(out ec, out p1, out p2, 0)\r
) {\r
// Write the event name to the debug window\r
Debug.WriteLine(ec.ToString());\r
}\r
\r
// Release any resources the message allocated\r
- hr = m_mediaEvent.FreeEventParams(ec, p1, p2);\r
+ hr = graph.MediaEvent.FreeEventParams(ec, p1, p2);\r
DsError.ThrowExceptionForHR(hr);\r
\r
//lock (tcLock) {\r
using System.Security;\r
using System.Windows.Forms;\r
\r
+//https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/mapping-stream-formats-to-speaker-configurations\r
namespace DxPlay {\r
#region "LAV COM classes"\r
\r
--- /dev/null
+using DirectShowLib;\r
+using DirectShowLib.Utils;\r
+using NLog;\r
+using System;\r
+using System.Runtime.InteropServices;\r
+\r
+namespace DxPlay {\r
+ public class PlayerGraph : FilterGraph, IDisposable {\r
+ #if DEBUG\r
+ private DsROTEntry m_DsRot;\r
+ #endif\r
+ private static readonly Logger logger = LogManager.GetCurrentClassLogger();\r
+ public IVideoWindow VideoWindow { get; private set; }\r
+ public ISampleGrabber SampleGrabber { get; private set; }\r
+ public IMediaSeeking MediaSeeking { get; private set; }\r
+ public IMediaControl MediaControl { get; private set; }\r
+ public IMediaEvent MediaEvent { get; private set; }\r
+\r
+ public PlayerGraph(string fileName) {\r
+ try {\r
+ MediaSeeking = this as IMediaSeeking;\r
+ MediaControl = this as IMediaControl;\r
+ MediaEvent = this as IMediaEvent;\r
+ VideoWindow = this as IVideoWindow;\r
+ IGraphBuilder graphBuilder = this as IGraphBuilder;\r
+#if DEBUG\r
+ m_DsRot = new DsROTEntry(graphBuilder);\r
+#endif\r
+ logger.Debug("Add SourceFilter to graph");\r
+ DsError.ThrowExceptionForHR(graphBuilder.AddSourceFilter(fileName, fileName, out IBaseFilter sourceFilter));\r
+\r
+ IBaseFilter splitter = AddSplitter(graphBuilder, sourceFilter);\r
+ IBaseFilter videoDecoder = AddVideoDecoder(graphBuilder, splitter);\r
+ IBaseFilter sampleGrabber = AddSampleGrabber(graphBuilder, videoDecoder);\r
+ SampleGrabber = (ISampleGrabber)sampleGrabber;\r
+ IBaseFilter videoRenderer = AddRenderer(graphBuilder, sampleGrabber);\r
+ if (DsFindPin.ByName(splitter, "Audio") != null) {\r
+ IBaseFilter audioDecoder = AddAudioDecoder(graphBuilder, splitter);\r
+ FilterGraphTools.RenderPin(graphBuilder, audioDecoder, "Output");\r
+ } else {\r
+ logger.Warn("Audio pin not available");\r
+ }\r
+\r
+ SearchAudioTracks(splitter);\r
+ EnableDeinterlace(videoDecoder);\r
+ }\r
+ catch (Exception e) {\r
+ logger.Error(e.Message);\r
+ }\r
+ }\r
+\r
+ private void EnableDeinterlace(IBaseFilter videoDecoder) {\r
+ logger.Debug("Enable YADIF deinterlace");\r
+ ILAVVideoSettings settings = (ILAVVideoSettings)videoDecoder;\r
+ settings.SetSWDeintMode(LAVSWDeintModes.SWDeintMode_YADIF);\r
+ settings.SetSWDeintOutput(LAVDeintOutput.DeintOutput_FramePer2Field);\r
+ }\r
+\r
+ private IBaseFilter AddAudioDecoder(IGraphBuilder graphBuilder, IBaseFilter splitter) {\r
+ logger.Debug("Add LAVAudio to graph");\r
+ IBaseFilter audioDecoder = null;\r
+ audioDecoder = LoadAudioDecoder(graphBuilder);\r
+ if (audioDecoder == null)\r
+ throw new Exception("No audio decoder!");\r
+\r
+ logger.Debug("Connect LAVSplitter -> LAVAudio");\r
+ FilterGraphTools.ConnectFilters(graphBuilder, splitter, "Audio", audioDecoder, "Input", true);\r
+ return audioDecoder;\r
+ }\r
+\r
+ private IBaseFilter AddRenderer(IGraphBuilder graphBuilder, IBaseFilter sampleGrabber) {\r
+ logger.Debug("Add VideoMixingRenderer9 to graph");\r
+ IBaseFilter videoRenderer = (IBaseFilter)new VideoMixingRenderer9();\r
+ DsError.ThrowExceptionForHR(graphBuilder.AddFilter(videoRenderer, "Video Mixing Renderer 9"));\r
+\r
+ logger.Debug("Connect SampleGrabber -> VideoMixingRenderer9");\r
+ FilterGraphTools.ConnectFilters(graphBuilder, sampleGrabber, "Output", videoRenderer, "VMR Input0", true);\r
+ return videoRenderer;\r
+ }\r
+\r
+ private IBaseFilter AddSampleGrabber(IGraphBuilder graphBuilder, IBaseFilter videoDecoder) {\r
+ logger.Debug("Add SampleGrabber to graph");\r
+ IBaseFilter grabber = (IBaseFilter)new SampleGrabber();\r
+ DsError.ThrowExceptionForHR(graphBuilder.AddFilter(grabber, "Sample Grabber"));\r
+ logger.Debug("Connect LAVVideo -> SampleGrabber");\r
+ FilterGraphTools.ConnectFilters(graphBuilder, videoDecoder, "Output", grabber, "Input", true);\r
+ return grabber;\r
+ }\r
+\r
+ private IBaseFilter AddVideoDecoder(IGraphBuilder graphBuilder, IBaseFilter splitter) {\r
+ logger.Debug("Add LAVVideo to graph");\r
+ IBaseFilter videoDecoder = LoadVideoDecoder(graphBuilder);\r
+\r
+ if (videoDecoder == null)\r
+ throw new Exception("No video decoder!");\r
+\r
+ logger.Debug("Connect LAVSplitter -> LAVVideo");\r
+ FilterGraphTools.ConnectFilters(graphBuilder, splitter, "Video", videoDecoder, "Input", true);\r
+ return videoDecoder;\r
+ }\r
+\r
+ private IBaseFilter AddSplitter(IGraphBuilder graphBuilder, IBaseFilter sourceFilter) {\r
+ logger.Debug("Add LAVSplitter to graph");\r
+ IBaseFilter splitter = LoadSplitter(graphBuilder);\r
+ if (splitter == null)\r
+ throw new Exception("No splitter!");\r
+ logger.Debug("Connect SourceFilter -> LAVSplitter");\r
+ FilterGraphTools.ConnectFilters(graphBuilder, sourceFilter, "Output", splitter, "Input", true);\r
+ return splitter;\r
+ }\r
+\r
+ private void SearchAudioTracks(IBaseFilter splitter) {\r
+ IAMStreamSelect amStreamSelect = (IAMStreamSelect)splitter;\r
+ if (amStreamSelect != null) {\r
+ int count = 0;\r
+ amStreamSelect.Count(out count);\r
+ int audioCount = 0;\r
+ for (int i = 0; i < count; i++) {\r
+ amStreamSelect.Info(i, out AMMediaType ppmt, out AMStreamSelectInfoFlags pdwFlags, out int plcid, out int pdwGroup, out string ppszName, out object ppObject, out object ppUnk);\r
+ if (ppmt.majorType == MediaType.Audio) {\r
+ logger.Debug("Found audio channel");\r
+ audioCount++;\r
+ }\r
+ DsUtils.FreeAMMediaType(ppmt);\r
+ if (ppObject != null)\r
+ DsUtils.ReleaseComObject(ppObject);\r
+ if (ppUnk != null)\r
+ DsUtils.ReleaseComObject(ppUnk);\r
+ }\r
+ logger.Debug("Audio count: " + audioCount);\r
+ }\r
+ }\r
+\r
+ private IBaseFilter LoadVideoDecoder(IGraphBuilder graphBuilder) {\r
+ IBaseFilter videoDecoder = null;\r
+ ILAVVideoSettings lavVideoSettings;\r
+ videoDecoder = FilterProvider.GetVideoFilter(out lavVideoSettings);\r
+ if (videoDecoder == null)\r
+ videoDecoder = FilterGraphTools.AddFilterByName(graphBuilder, FilterCategory.LegacyAmFilterCategory, "LAV Video Decoder");\r
+ else\r
+ graphBuilder.AddFilter(videoDecoder, "LAV Video Decoder");\r
+ return videoDecoder;\r
+ }\r
+\r
+ private IBaseFilter LoadAudioDecoder(IGraphBuilder graphBuilder) {\r
+ IBaseFilter audioDecoder = null;\r
+ ILAVAudioSettings lavAudioSettings;\r
+ ILAVAudioStatus lavAudioStatus;\r
+ audioDecoder = FilterProvider.GetAudioFilter(out lavAudioSettings, out lavAudioStatus);\r
+ if (audioDecoder == null)\r
+ audioDecoder = FilterGraphTools.AddFilterByName(graphBuilder, FilterCategory.LegacyAmFilterCategory, "LAV Audio Decoder");\r
+ else\r
+ graphBuilder.AddFilter(audioDecoder, "LAV Audio Decoder");\r
+ return audioDecoder;\r
+ }\r
+\r
+ private IBaseFilter LoadSplitter(IGraphBuilder graphBuilder) {\r
+ IBaseFilter splitter = null;\r
+ ILAVSplitterSettings lavSplitterSettings;\r
+ splitter = FilterProvider.GetSplitter(out lavSplitterSettings);\r
+ if (splitter == null)\r
+ splitter = FilterGraphTools.AddFilterByName(graphBuilder, FilterCategory.LegacyAmFilterCategory, "LAV Splitter");\r
+ else\r
+ graphBuilder.AddFilter(splitter, "LAV Splitter");\r
+ return splitter;\r
+ }\r
+\r
+ // Shut down capture\r
+ public void Dispose() {\r
+ logger.Debug("CloseInterfaces");\r
+ lock (this) {\r
+#if DEBUG\r
+ if (m_DsRot != null)\r
+ m_DsRot.Dispose();\r
+#endif\r
+ IMediaControl mediaCtrl = (IMediaControl) this;\r
+ if (mediaCtrl != null) {\r
+ mediaCtrl.Stop();\r
+ IGraphBuilder graphBuilder = (IGraphBuilder)mediaCtrl;\r
+ FilterGraphTools.DisconnectAllPins(graphBuilder);\r
+ FilterGraphTools.RemoveAllFilters(graphBuilder);\r
+ }\r
+\r
+ Marshal.ReleaseComObject(this);\r
+ }\r
+ }\r
+\r
+ }\r
+}\r
"active": false,\r
"executeimmediate": false,\r
"name" : "SYS: recreate-lowres",\r
- "template": "recreate-lowres.xml",\r
+ "template": "sys-recreate-lowres.xml",\r
"parameters": [ \r
{"name": "filePath", "value": "c:/_downloads/Silicon.Valley.S04E08.HDTV.x264.HUN-SFY/Silicon.Valley.S04E08.HDTV.x264.HUN-SFY.mkv", "type": "java.lang.String" }\r
]\r
<executor className="user.jobengine.server.steps.ArchiveListBuilderStep" maxConcurrent="1"/>\r
<executor className="user.jobengine.server.steps.ArchiveMaterialSubmitStep" maxConcurrent="1"/>\r
<executor className="user.jobengine.server.steps.BatchRetrieveForkStep" maxConcurrent="10"/>\r
+ <executor className="user.jobengine.server.steps.CheckLOWRESIntegrity" maxConcurrent="1"/>\r
<executor className="user.jobengine.server.steps.CheckMORPHEUSMissingMaterialsStep" maxConcurrent="1"/>\r
<executor className="user.jobengine.server.steps.CheckTRAFFICMissingMaterialsStep" maxConcurrent="1"/>\r
<executor className="user.jobengine.server.steps.CleanupMountedLocationStep" maxConcurrent="10"/>\r
<executor className="user.jobengine.server.steps.TSMRetrieveMissingMaterialStep" maxConcurrent="1"/>\r
<executor className="user.jobengine.server.steps.UploadRecordingToNexioStep" maxConcurrent="1"/>\r
<executor className="user.jobengine.server.steps.MediaToolStep" maxConcurrent="1"/>\r
- \r
</executors>
\ No newline at end of file
{"joblist":[\r
+ {\r
+ "name" : "sys: Check LOWRES integrity",\r
+ "template": "check-lowres-integrity.xml",\r
+ "parameters": [ \r
+ {"name": "webPath", "value": "/mediacube/data/lowres/www/video", "type": "java.lang.String"}\r
+ ]\r
+ },\r
{\r
"active": false,\r
"executeimmediate": false,\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<jobtemplate name="Felhasználói archiválás">\r
+ <declarations>\r
+ <parameters>\r
+ <parameter name="webPath" type="java.lang.String" />\r
+ </parameters>\r
+ </declarations>\r
+ <commands>\r
+ <calljobstep type="user.jobengine.server.steps.CheckLOWRESIntegrity" weight="1">\r
+ <inputs>\r
+ <input>\r
+ <parameter name="webPath" />\r
+ </input>\r
+ </inputs>\r
+ </calljobstep>\r
+ </commands>\r
+</jobtemplate>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<jobtemplate name="Visszarögzített anyagok archiválása mappából">\r
+ <declarations>\r
+ <parameters>\r
+ <parameter name="localHiresPath" type="java.lang.String" />\r
+ <parameter name="globalHiresPath" type="java.lang.String" />\r
+ </parameters>\r
+ <variables>\r
+ <variable name="mediaCubeMedia" type="user.jobengine.db.Media" />\r
+ <variable name="targetNamePattern" type="java.lang.String" />\r
+ <variable name="archiveItem" type="user.jobengine.server.steps.ArchiveItem" />\r
+ <variable name="killDateDays" type="java.lang.Integer"/>\r
+ <variable name="successRecipient" type="java.lang.String" />\r
+ <variable name="deleteSource" type="java.lang.Boolean"/>\r
+ </variables>\r
+ </declarations>\r
+ <commands>\r
+ <calljobstep type="user.jobengine.server.steps.DetectMissingLengthStep" weight="1">\r
+ <inputs>\r
+ <input>\r
+ <parameter name="localHiresPath" />\r
+ </input>\r
+ </inputs>\r
+ <outputs>\r
+ <output>\r
+ <variable name="mediaCubeMedia" />\r
+ </output>\r
+ <output>\r
+ <variable name="archiveItem" />\r
+ </output>\r
+ <output>\r
+ <variable name="targetNamePattern" />\r
+ </output>\r
+ <output>\r
+ <variable name="successRecipient" />\r
+ </output>\r
+ <output>\r
+ <variable name="killDateDays" />\r
+ </output>\r
+ <output>\r
+ <variable name="deleteSource" />\r
+ </output>\r
+ </outputs>\r
+ </calljobstep>\r
+ <calljobstep type="user.jobengine.server.steps.TSMRestoreStep" weight="1">\r
+ <inputs>\r
+ <input>\r
+ <variable name="mediaCubeMedia" />\r
+ </input>\r
+ <input>\r
+ <parameter name="localHiresPath" />\r
+ </input>\r
+ <input>\r
+ <variable name="targetNamePattern" />\r
+ </input>\r
+ <input>\r
+ <variable name="successRecipient" />\r
+ </input>\r
+ <input>\r
+ <variable name="killDateDays" />\r
+ </input>\r
+ </inputs>\r
+ </calljobstep>\r
+ <calljobstep type="user.jobengine.server.steps.MediaToolStep" weight="1">\r
+ <inputs>\r
+ <input>\r
+ <variable name="archiveItem" />\r
+ </input>\r
+ <input>\r
+ <variable name="mediaCubeMedia" />\r
+ </input>\r
+ </inputs>\r
+ </calljobstep>\r
+ </commands>\r
+</jobtemplate>
\ No newline at end of file
--- /dev/null
+package user.jobengine.server.steps;\r
+\r
+import java.nio.file.Path;\r
+import java.nio.file.Paths;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.apache.logging.log4j.LogManager;\r
+import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
+\r
+import user.jobengine.db.IItemManager;\r
+import user.jobengine.db.IResultSetConsumer;\r
+import user.jobengine.db.Media;\r
+import user.jobengine.db.MediaFile;\r
+import user.jobengine.server.IJobEngine;\r
+import user.jobengine.server.IJobRuntime;\r
+\r
+public class CheckLOWRESIntegrity extends JobStep {\r
+ private static final Logger logger = LogManager.getLogger();\r
+ private IItemManager manager;\r
+ private Marker marker;\r
+ private String webPath;\r
+\r
+ private void checkIntegrity(MediaFile mediaFile) {\r
+ Path path = Paths.get(webPath, mediaFile.getRelativePath());\r
+ if (!path.toFile().exists()) {\r
+ logger.warn(marker, "{} {}", mediaFile.getId(), path);\r
+ }\r
+ }\r
+\r
+ @StepEntry\r
+ public Object[] execute(String webPath, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+ this.webPath = webPath;\r
+ marker = jobRuntime.getMarker();\r
+ manager = jobEngine.getItemManager();\r
+ List<Long> mediaIdentities = getTranscodedMediaIdentities();\r
+ int allCount = mediaIdentities.size();\r
+ int currentCount = 0;\r
+ for (long id : mediaIdentities) {\r
+ Media media = manager.getMedia(id);\r
+ List<MediaFile> mediaFiles = media.getMediaFiles();\r
+ for (MediaFile mediaFile : mediaFiles) {\r
+ if (mediaFile.getStoreId() == 21)\r
+ checkIntegrity(mediaFile);\r
+ }\r
+ currentCount++;\r
+ jobRuntime.incrementProgress(currentCount * 100 / allCount);\r
+ }\r
+ return null;\r
+ }\r
+\r
+ public List<Long> getTranscodedMediaIdentities() {\r
+ final List<Long> result = new ArrayList<>();\r
+ String query = "select mediaid from vw_mediafiles where mediafilecount = 2";\r
+\r
+ IResultSetConsumer consumer = rs -> {\r
+ result.add(rs.getLong("mediaId"));\r
+ return true;\r
+ };\r
+\r
+ manager.executeQuery(query, consumer, null);\r
+ return result;\r
+ }\r
+\r
+}\r
import org.apache.commons.net.ftp.FTPReply;\r
import org.apache.logging.log4j.LogManager;\r
import org.apache.logging.log4j.Logger;\r
+import org.apache.logging.log4j.Marker;\r
\r
import com.ibm.nosql.json.api.BasicDBObject;\r
import com.ibm.nosql.json.api.DB;\r
private StoreUri targetUri;\r
private int nexioKillDateDays;\r
private String nexioAgency;\r
+ private Marker systemMarker;\r
\r
private int check(int value, String name) {\r
if (value == 0) {\r
- logger.error(getMarker(), "A folyamat '{}' bemeneti paramétere 0.", name);\r
+ logger.error(systemMarker, "A folyamat '{}' bemeneti paramétere 0.", name);\r
throw new NullPointerException(String.format("System is not configured properly, missing '%s' input parameter.", name));\r
}\r
return value;\r
\r
private String check(String value, String name) {\r
if (value == null) {\r
- logger.error(getMarker(), "A folyamat '{}' bemeneti paramétere üres.", name);\r
+ logger.error(systemMarker, "A folyamat '{}' bemeneti paramétere üres.", name);\r
throw new NullPointerException(String.format("System is not configured properly, missing '%s' input parameter.", name));\r
}\r
return value;\r
try {\r
copyFile(fileArchive, rundownArchive, storyArchive);\r
} catch (Exception e) {\r
- logger.error(getMarker(), "A '{}' clip archiválása sikertelen. A rendszer üzenete: {}", fileArchive.getFileName(), e.getMessage());\r
+ logger.error(systemMarker, "A '{}' clip archiválása sikertelen. A rendszer üzenete: {}", fileArchive.getFileName(), e.getMessage());\r
}\r
}\r
}\r
@StepEntry\r
public Object[] execute(int nexioPort, String nexioUserName, String nexioPassword, String archiveFtp, String archiveUserName, String archivePassword,\r
int daysBeforeNow, int nexioKillDateDays, String nexioAgency, IJobEngine jobEngine, IJobRuntime jobRuntime) throws Exception {\r
+ systemMarker = jobRuntime.getMarker();\r
setAndCheck(nexioPort, nexioUserName, nexioPassword, archiveFtp, archiveUserName, archivePassword, nexioKillDateDays, nexioAgency, jobEngine);\r
octopusAPI = new OctopusAPI();\r
Calendar scheduledDate = Calendar.getInstance();\r
scheduledDate.add(Calendar.DAY_OF_YEAR, -1 * daysBeforeNow);\r
List<DBObject> rundowns = octopusAPI.getRundowns(scheduledDate.getTime());\r
if (rundowns == null) {\r
- logger.warn(getMarker(), "Nem található adástükör a {} napra.", CalendarUtils.toDateString(scheduledDate));\r
+ logger.warn(systemMarker, "Nem található adástükör a {} napra.", CalendarUtils.toDateString(scheduledDate));\r
return null;\r
}\r
\r
db.getCollection(ARCHIVEDRUNDOWNS).save(currentRundownID);\r
} catch (Exception e) {\r
logger.catching(e);\r
- logger.error(getMarker(),\r
+ logger.error(systemMarker,\r
String.format("A %s %s tükör archiválása nem lehetséges, mert a annak ellenőrzése hibát jelzett. A rendszer üzenete: %s", rundownID,\r
rundownName, e.getMessage()));\r
}\r
int nexioKillDateDays, String nexioAgency, IJobEngine jobEngine) throws Exception {\r
db = NoSQLUtils.getNoSQLDB();\r
if (db == null) {\r
- logger.error(getMarker(), "Az NoSQL adatkezelő réteg nem elérhető.");\r
+ logger.error(systemMarker, "Az NoSQL adatkezelő réteg nem elérhető.");\r
throw new NullPointerException("Internal error, missing NoSQL DB reference.");\r
}\r
\r
if (jobEngine == null) {\r
- logger.error(getMarker(), "Az folyamatkezelő réteg nem elérhető.");\r
+ logger.error(systemMarker, "Az folyamatkezelő réteg nem elérhető.");\r
throw new NullPointerException("Internal error, missing JobEngine reference.");\r
}\r
manager = jobEngine.getItemManager();\r
if (manager == null) {\r
- logger.error(getMarker(), "Az adatbáziskezelő réteg nem elérhető.");\r
+ logger.error(systemMarker, "Az adatbáziskezelő réteg nem elérhető.");\r
throw new NullPointerException("Internal error, missing ItemManager reference.");\r
}\r
String nexioHost = System.getProperty("nexio.host");\r
if (StringUtils.isBlank(nexioHost)) {\r
- logger.error(getMarker(), "A 'nexio.host' rendszer paraméter nem található.");\r
+ logger.error(systemMarker, "A 'nexio.host' rendszer paraméter nem található.");\r
throw new NullPointerException("System is not configured properly, 'jobengine.selenio.address' startup parameter missing.");\r
}\r
check(nexioPort, "nexioPort");\r
sourceUri.setUserName(nexioUserName);\r
sourceUri.setPassword(nexioPassword);\r
if (sourceUri == null) {\r
- logger.error(getMarker(), "A forrás nem elérhető.");\r
+ logger.error(systemMarker, "A forrás nem elérhető.");\r
throw new NullPointerException("Internal error, missing 'sourceUri'.");\r
}\r
\r
targetUri.setUserName(archiveUserName);\r
targetUri.setPassword(archivePassword);\r
if (targetUri == null) {\r
- logger.error(getMarker(), "A cél nem elérhető.");\r
+ logger.error(systemMarker, "A cél nem elérhető.");\r
throw new NullPointerException("Internal error, missing 'targetUri'.");\r
}\r
\r
logger.info("Transfer chunk {}", fileName);\r
OutputStream outStream = null;\r
try {\r
+ targetFtp = ((FtpDirectoryLister) targetUri.getLister()).connect();\r
outStream = targetFtp.storeFileStream(fileName + MXFEXT);\r
if (outStream == null) {\r
throw new NullPointerException("Can not open: " + fileName + MXFEXT + " Reply:" + targetFtp.getReplyString());\r
\r
for (Media media : medias) {\r
String name = media.getMediaFilesName();\r
+ if (name == null)\r
+ continue;\r
DBObject existing = collection.findOne(new BasicDBObject("name", name));\r
if (existing != null)\r
continue;\r
import user.jobengine.server.JobEngineException;\r
\r
public class TSMBackupStep extends JobStep {\r
+ private static final String MXFEXT = ".MXF";\r
private static final Logger logger = LogManager.getLogger();\r
private IItemManager manager;\r
private File sourceMediaFile;\r
\r
jobRuntime.setDescription(String.format("%s: %s", jobRuntime.getDescription(), details));\r
\r
- if (archiveItem.getExistingMediaId() == 0) {\r
+ //A dupla ellenorzes a napon beluli ismetlesek miatt kell\r
+ long existingMediaId = archiveItem.getExistingMediaId();\r
+ if (existingMediaId == 0)\r
+ existingMediaId = manager.getExistingRundownMedia(sourceFileName.replace(MXFEXT, ""));\r
+\r
+ if (existingMediaId == 0) {\r
StoreUri sourceUri = manager.createStoreUri(RemoteStoreProtocol.LOCAL, sourceMediaFile.getParent().toString());\r
\r
final IJobRuntime runtime = jobRuntime;\r
} else {\r
logger.info(marker, "Az '{}' TSM mentése nem szükséges, mert már megtalálható az archívumban.", sourceFileName);\r
}\r
- saveMetadata(mediaCubeMedia, sourceFileName, archiveItem);\r
+ saveMetadata(mediaCubeMedia, sourceFileName, existingMediaId);\r
logger.info(marker, "Az '{}' archiválása sikeres.", sourceFileName);\r
\r
if (killDateDays > 0)\r
return null;\r
}\r
\r
- private void saveMetadata(Media mediaCubeMedia, String sourceFileName, ArchiveItem archiveItem) {\r
- if (archiveItem.getExistingMediaId() == 0) {\r
+ private void saveMetadata(Media mediaCubeMedia, String sourceFileName, long existingMediaId) {\r
+\r
+ if (existingMediaId == 0) {\r
MediaFile mediaFile = manager.createMediaFile(sourceFileName, fileType, tsmStore, mediaCubeMedia);\r
mediaFile.setHouseId(sourceFileName);\r
mediaFile.add();\r
} else {\r
- Media existingMedia = manager.getMedia(archiveItem.getExistingMediaId());\r
+ Media existingMedia = manager.getMedia(existingMediaId);\r
List<MediaFile> mediaFiles = existingMedia.getMediaFiles();\r
if (mediaFiles != null) {\r
for (MediaFile mf : mediaFiles) {\r
String details = String.format("%s (%d bytes)", sourceFileName, sourceMediaFile.length());\r
Path targetPath = null;\r
try {\r
- String sourceFile = Paths.get(globalHiresSourcePath, sourceFileName).toString();\r
- IFFAStransAPI api = new FFAStransAPI(transcoderAddress, p -> {\r
- if (p <= 100)\r
- jobRuntime.incrementProgress(p);\r
- });\r
- api.submit(transcoderTemplateName, sourceFile);\r
- jobRuntime.setDescription(String.format("%s: %s", jobRuntime.getDescription(), details));\r
- api.monitor(1000);\r
targetPath = Paths.get(localLowresTargetPath, sourceFileName.replace(MXFEXT, MP4EXT));\r
+ if (!targetPath.toFile().exists()) {\r
+ jobRuntime.setDescription(String.format("%s: %s", jobRuntime.getDescription(), details));\r
+ String sourceFile = Paths.get(globalHiresSourcePath, sourceFileName).toString();\r
+ IFFAStransAPI api = new FFAStransAPI(transcoderAddress, p -> {\r
+ if (p <= 100)\r
+ jobRuntime.incrementProgress(p);\r
+ });\r
+\r
+ api.submit(transcoderTemplateName, sourceFile);\r
+ api.monitor(1000);\r
+ }\r
+\r
postprocess(targetPath, webPath);\r
+\r
} catch (Exception e) {\r
logger.catching(e);\r
Message m = new ParameterizedMessage("Az '{}' állomány átkódolása sikertelen. A rendszer hibaüzenete: {}", details, e.getMessage());\r
Path lowresPath = null;\r
try {\r
String transcodedFileName = transcodedFilePath.getFileName().toString();\r
+ String targetPath = null;\r
if (transcodedFileName.indexOf(".") > 2) {\r
Path subdir = Paths.get(transcodedFileName.substring(0, 1), transcodedFileName.substring(1, 2), transcodedFileName.substring(2, 3));\r
- manager.createMediaFile(Paths.get(subdir.toString(), transcodedFileName).toString(), fileType, store, mediaCubeMedia).add();\r
EscortFiles.ensureUNCFolder(webPath, subdir.toString());\r
- lowresPath = Paths.get(webPath, subdir.toString(), transcodedFileName);\r
- Files.move(transcodedFilePath, lowresPath);\r
+ targetPath = Paths.get(subdir.toString(), transcodedFileName).toString();\r
} else {\r
- manager.createMediaFile(transcodedFileName, fileType, store, mediaCubeMedia).add();\r
- lowresPath = Paths.get(webPath, transcodedFileName);\r
- Files.move(transcodedFilePath, lowresPath);\r
+ targetPath = transcodedFileName;\r
+ }\r
+ lowresPath = Paths.get(webPath, targetPath);\r
+ int version = 1;\r
+ while (lowresPath.toFile().exists()) {\r
+ String fileName = transcodedFileName + version + MP4EXT;\r
+ lowresPath = Paths.get(lowresPath.toString().replace(transcodedFileName, fileName));\r
+ targetPath = targetPath.replace(transcodedFileName, fileName);\r
+ transcodedFileName = fileName;\r
+ version++;\r
}\r
+\r
+ Files.move(transcodedFilePath, lowresPath);\r
+ manager.createMediaFile(targetPath, fileType, store, mediaCubeMedia).add();\r
} catch (IOException e) {\r
logger.catching(e);\r
logger.error(marker, "A '{}' állomány mozgatása a '{}' helyre nem sikerült.", transcodedFilePath, lowresPath);\r
\r
public class TranscodeSELENIOStep extends JobStep {\r
\r
+ private static final String MXFEXT = ".MXF";\r
private static final String LOWRES_FILETYPE = "Low-res";\r
private static final Logger logger = LogManager.getLogger();\r
private final List<State> showStoppers = Arrays.asList(State.CANCELLED, State.COMPLETE, State.FAILED);\r
marker = jobRuntime.getMarker();\r
String sourceFileName = null;\r
\r
- //Nincs mit transzkódolni\r
- if (archiveItem.getExistingMediaId() != 0)\r
- return null;\r
-\r
try {\r
setAndCheck(globalSourcePath, transcoderTargetPath, webPath, jobEngine);\r
\r
File sourceMediaFile = new File(archiveItem.getMediaFile());\r
sourceFileName = sourceMediaFile.getName();\r
+\r
+ //Nincs mit transzkódolni, a TSMBackupStep csinal masolatot a mediafileokrol\r
+ //A dupla ellenorzes a napon beluli ismetlesek miatt kell\r
+ long existingMediaId = archiveItem.getExistingMediaId();\r
+ if (existingMediaId == 0)\r
+ existingMediaId = manager.getExistingRundownMedia(sourceFileName.replace(MXFEXT, ""));\r
+ if (existingMediaId != 0)\r
+ return null;\r
+\r
String details = String.format("%s (%d bytes)", sourceFileName, sourceMediaFile.length());\r
\r
Path inputPath = Paths.get(globalSourcePath, sourceFileName);\r
private ResteasyWebTarget webTarget;\r
private IProgressChangedListener listener;\r
private String jobId;\r
+ private BasicDBObject lastJobToSubmit;\r
\r
public FFAStransAPI(String apiAddress, IProgressChangedListener listener) {\r
this.listener = listener;\r
webTarget = new ResteasyClientBuilder().build().target(apiAddress);\r
}\r
\r
+ private void doSubmit() throws Exception {\r
+ ResteasyWebTarget target = webTarget.path("jobs");\r
+ Response apiResponse = target.request().post(Entity.entity(lastJobToSubmit.toString(), MediaType.APPLICATION_JSON));\r
+ if (apiResponse.getStatus() != 202)\r
+ throw new Exception("Can not submit, response status is: " + apiResponse.getStatus());\r
+ String json = apiResponse.readEntity(String.class);\r
+ logger.info("Transoder response: {}", json);\r
+ if (StringUtils.isBlank(json))\r
+ throw new Exception("Can not submit, response JSON is empty");\r
+ BasicDBObject resultObject = (BasicDBObject) JSONUtil.jsonToDbObject(json);\r
+ if (resultObject == null)\r
+ throw new Exception("Can not submit, response object is null");\r
+ jobId = resultObject.getString("job_id");\r
+ }\r
+\r
@Override\r
public BasicDBObject getHistory(String jobStart) {\r
ResteasyWebTarget target = webTarget.path("history");\r
//System.out.println("Progress: " + 100);\r
listener.onProgressChanged(100);\r
BasicDBObject history = getHistory(jobStart);\r
+\r
+ if (history == null && lastJobToSubmit != null) {\r
+ //plusz 1 proba\r
+ doSubmit();\r
+ lastJobToSubmit = null;\r
+ monitor(pollIntervall);\r
+ return;\r
+ }\r
+\r
//System.out.println("History: " + history.toPrettyString(null));\r
if (history == null || NoSQLUtils.asLong(history, "state") != 1) {\r
String error = NoSQLUtils.asString(history, "outcome");\r
if (wfID < 0)\r
throw new Exception("Workflow not exists: " + workflowName);\r
\r
- BasicDBObject job = new BasicDBObject("wf_id", wfID).append("inputfile", inputFile);\r
- ResteasyWebTarget target = webTarget.path("jobs");\r
- Response apiResponse = target.request().post(Entity.entity(job.toString(), MediaType.APPLICATION_JSON));\r
- if (apiResponse.getStatus() != 202)\r
- throw new Exception("Can not submit, response status is: " + apiResponse.getStatus());\r
- String json = apiResponse.readEntity(String.class);\r
- logger.info("Transoder response: {}", json);\r
- if (StringUtils.isBlank(json))\r
- throw new Exception("Can not submit, response JSON is empty");\r
- BasicDBObject resultObject = (BasicDBObject) JSONUtil.jsonToDbObject(json);\r
- if (resultObject == null)\r
- throw new Exception("Can not submit, response object is null");\r
- jobId = resultObject.getString("job_id");\r
+ lastJobToSubmit = new BasicDBObject("wf_id", wfID).append("inputfile", inputFile);\r
+ doSubmit();\r
}\r
}\r
---MEDIAFILE\r
-select mediaid from vw_mediafiles where mediafilecount = 1\r
+--Hamis LOWRES\r
+drop view vw_mediafiles_path\r
+create view vw_mediafiles_path as\r
+select relativepath, count(*) as count from mediafile where storeid=21 group by relativepath\r
+\r
+select * from mediafile mf, vw_mediafiles_path v where v.count > 1 and mf.RELATIVEPATH = v.RELATIVEPATH order by v.count, mf.relativepath, mf.id\r
+\r
+--MEDIAFILE\r
+select count(*) from vw_mediafiles where mediafilecount = 0\r
+\r
+select * from mediafile where relativepath = ''\r
\r
select * from mediafile f where f.mediaid in (select mediaid from vw_mediafiles where mediafilecount = 1)\r
--delete from mediafile f where f.mediaid in (select mediaid from vw_mediafiles where mediafilecount = 1)\r
</servlet-mapping>\r
\r
<session-config>\r
- <session-timeout>15</session-timeout>\r
+ <!-- percben -->\r
+ <session-timeout>60</session-timeout>\r
</session-config>\r
+\r
<welcome-file-list>\r
<welcome-file>index.html</welcome-file>\r
<welcome-file>index.htm</welcome-file>\r
<welcome-file>index.zul</welcome-file>\r
<welcome-file>index.zhtml</welcome-file>\r
</welcome-file-list>\r
+\r
+ <security-constraint>\r
+ <web-resource-collection>\r
+ <web-resource-name>Everything on the app</web-resource-name>\r
+ <url-pattern>/*</url-pattern>\r
+ </web-resource-collection>\r
+ <user-data-constraint>\r
+ <transport-guarantee>CONFIDENTIAL</transport-guarantee>\r
+ </user-data-constraint>\r
+ </security-constraint>\r
</web-app>\r
<timeout-message>Lejárt a munkamenet, kérem töltse be újra az alkalmazást.</timeout-message>\r
<!-- timeout-uri>/timeout.zul</timeout-uri -->\r
<automatic-timeout/>\r
+ <!-- masodpercben -->\r
<!-- <session-timeout>900</session-timeout> -->\r
</session-config>\r
\r
-version=2.3.7\r
+version=2.3.8\r
footer=2016 © Copyright User Rendszerház Kft.\r
\r
login_info=Információ\r
package user.jobengine.server.IT;\r
\r
import java.io.File;\r
+import java.io.IOException;\r
import java.nio.charset.Charset;\r
import java.nio.file.Files;\r
import java.nio.file.Path;\r
import java.util.Calendar;\r
import java.util.Collections;\r
import java.util.Date;\r
+import java.util.HashMap;\r
import java.util.LinkedHashMap;\r
+import java.util.LinkedHashSet;\r
import java.util.List;\r
import java.util.Map;\r
+import java.util.Set;\r
import java.util.function.Consumer;\r
import java.util.stream.Stream;\r
\r
+import org.apache.commons.lang.StringUtils;\r
import org.apache.commons.lang.time.DateUtils;\r
import org.junit.AfterClass;\r
import org.junit.BeforeClass;\r
import sqlj.runtime.ref.DefaultContext;\r
import user.commons.CalendarUtils;\r
import user.commons.IEntityBase;\r
+import user.commons.ListUtils;\r
import user.commons.logging.LogUtils;\r
import user.commons.nosql.NoSQLUtils;\r
+import user.commons.octopus.IOctopusAPI;\r
import user.commons.octopus.OctopusAPI;\r
import user.jobengine.db.IItemManager;\r
import user.jobengine.db.IResultSetConsumer;\r
\r
@BeforeClass\r
static public void setUpConnection() {\r
- System.setProperty("jobengine.octopus.rundowns.name", "test_rundowns");\r
- System.setProperty("jobengine.octopus.stories.name", "test_stories");\r
- System.setProperty("jobengine.octopus.storyfolders.name", "test_storyfolders");\r
+ // System.setProperty("jobengine.octopus.rundowns.name", "test_rundowns");\r
+ // System.setProperty("jobengine.octopus.stories.name", "test_stories");\r
+ // System.setProperty("jobengine.octopus.storyfolders.name", "test_storyfolders");\r
+ System.setProperty("jobengine.octopus.rundowns.name", "rundowns180608");\r
+ System.setProperty("jobengine.octopus.stories.name", "stories180608");\r
+ System.setProperty("jobengine.octopus.storyfolders.name", "storyfolders180608");\r
\r
System.setProperty("jobengine.nosql.db.url", "jdbc:db2://10.10.1.27:50000/mc:retrieveMessagesFromServerOnGetMessage=true;");\r
System.setProperty("jobengine.nosql.db.user", "db2admin");\r
return result;\r
}\r
\r
+ public Map<Media, List<String>> getExistingItemHouseIDs(String houseid) {\r
+ final Map<Media, List<String>> result = new HashMap<>();\r
+ final List<String> resultList = new ArrayList<>();\r
+ StringBuilder query = new StringBuilder();\r
+ query.append("select itemid, mediaid, replace(mediafilehouseid, concat('-', concat(itemhouseid,'.MXF')), '') filename");\r
+ query.append(" ");\r
+ query.append("from vw_items where replace(mediafilehouseid, concat('-', itemhouseid), '') != mediafilehouseid");\r
+ query.append(" ");\r
+ query.append("and replace(mediafilehouseid, concat('-', concat(itemhouseid,'.MXF')), '') = ?");\r
+ IStatementDecorator decorator = st -> {\r
+ st.setString(1, houseid);\r
+ };\r
+ IResultSetConsumer consumer = rs -> {\r
+ Media media = manager.getMedia(rs.getLong("mediaid"));\r
+\r
+ if (result.size() == 0)\r
+ result.put(media, resultList);\r
+\r
+ Item item = manager.getItem(media.getItemId());\r
+ resultList.add(item.getTitle());\r
+ return true;\r
+ };\r
+ manager.executeQuery(query.toString(), consumer, decorator);\r
+ return result;\r
+ }\r
+\r
+ private Item getRundownItem(BasicDBObject rundown) {\r
+\r
+ StringBuilder query = new StringBuilder();\r
+ query.append("select id from item where title=?");\r
+ IStatementDecorator decorator = st -> {\r
+ st.setString(1, getRundownTitle(rundown));\r
+ };\r
+ Item[] result = { null };\r
+ IResultSetConsumer consumer = rs -> {\r
+ Item item = manager.getItem(rs.getLong("id"));\r
+ result[0] = item;\r
+ return false;\r
+ };\r
+ manager.executeQuery(query.toString(), consumer, decorator);\r
+ return result[0];\r
+ }\r
+\r
+ private String getRundownTitle(BasicDBObject rundown) {\r
+ String name = NoSQLUtils.asString(NoSQLUtils.asDBObject(rundown, IOctopusAPI.RUNDOWN_TYPE), IOctopusAPI.NAME);\r
+ if (StringUtils.isBlank(name))\r
+ return null;\r
+ String channel = NoSQLUtils.asString(NoSQLUtils.asDBObject(rundown, IOctopusAPI.CHANNEL), IOctopusAPI.NAME);\r
+ Date scheduledStart = rundown.getDate(IOctopusAPI.SCHEDULED_START);\r
+ if (scheduledStart == null)\r
+ return null;\r
+ String start = CalendarUtils.toString(CalendarUtils.createCalendar(scheduledStart), "yyyy.MM.dd HH:mm");\r
+ return String.format("%s %s %s", start, name, channel);\r
+ }\r
+\r
private void processLowresDuplicateGroup(String fileName) {\r
System.out.println("*** Processing: " + fileName);\r
String query = "select mediafileid, mediafilehouseid, relativepath from vw_items_rd_lh where filename = ?";\r
return result;\r
}\r
\r
+ @Test\r
+ public void repairRundownChunks() throws Exception {\r
+ OctopusAPI octopusAPI = new OctopusAPI();\r
+ Path sourcePath = Paths.get("c:\\Temp\\__");\r
+ final Set<String> names = new LinkedHashSet<>();\r
+\r
+ try (Stream<Path> pathStream = Files.walk(sourcePath)) {\r
+ pathStream.forEach(new Consumer<Path>() {\r
+ @Override\r
+ public void accept(Path p) {\r
+ if (p.toFile().isDirectory())\r
+ return;\r
+ List<String> lines;\r
+ try {\r
+ lines = Files.readAllLines(p);\r
+ for (String line : lines) {\r
+ if (!line.contains("clip archiválása sikertelen. A rendszer üzenete: null"))\r
+ continue;\r
+ String[] splittedLine = line.split("'");\r
+ if (names.contains(splittedLine[1]))\r
+ continue;\r
+ names.add(splittedLine[1]);\r
+\r
+ //lenyeli a duplikalt hozzadast, lekezelni. addig nem futtathato!!!!!!!\r
+ Map<Media, List<String>> existing = getExistingItemHouseIDs(splittedLine[1]);\r
+\r
+ Media media = (Media) existing.keySet().toArray()[0];\r
+ List<String> itemTitles = (List<String>) existing.values().toArray()[0];\r
+ List<BasicDBObject> rundowns = ListUtils.cast(octopusAPI.getRundownsByPlaceHolderID(splittedLine[1]));\r
+ System.out.println(String.format("%s %d: ", splittedLine[1], media.getId()));\r
+\r
+ for (BasicDBObject rd : rundowns) {\r
+ String rundownTitle = getRundownTitle(rd);\r
+ if (itemTitles.contains(rundownTitle) || rundownTitle.contains("00:00"))\r
+ continue;\r
+\r
+ Item item = getRundownItem(rd);\r
+ if (item == null) {\r
+ item = manager.createItem("Generic", rundownTitle, null, NoSQLUtils.asString(rd, IOctopusAPI.ID));\r
+ item.add();\r
+ System.out.print(String.format("* %s,", rundownTitle));\r
+ } else {\r
+ System.out.print(String.format("%s (%d),", rundownTitle, item.getId()));\r
+ }\r
+\r
+ List<MediaFile> mediaFiles = media.getMediaFiles();\r
+ if (mediaFiles != null) {\r
+ for (MediaFile mf : mediaFiles) {\r
+ mf.setId(0);\r
+ mf.setMediaId(0);\r
+ }\r
+ }\r
+ media.setId(0);\r
+ media.setItemId(item.getId());\r
+ media.setPersister(manager);\r
+ media.add();\r
+\r
+ }\r
+\r
+ System.out.println();\r
+ }\r
+ } catch (IOException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ });\r
+ }\r
+\r
+ System.out.println(names.size());\r
+ }\r
+\r
+ @Test\r
+ public void test1() {\r
+ File sourceMediaFile = new File("c:/_downloads/mediacube-backlog-2018-05.pdf");\r
+ String sourceFileName = sourceMediaFile.getName();\r
+ String sourceFile = Paths.get("l:", sourceFileName).toString();\r
+ System.out.println(sourceFile);\r
+ }\r
+\r
}\r