//////////////////////////////////////////////////////////////////////////////////////// // Name: CPlayer::Skip (Public) // Description: // Skips to the specified segment in the sequencer source // Parameter: // SegmentID: [in] The segment identifier /////////////////////////////////////////////////////////////////////////////////////////// public int Skip(int SegmentID) { Debug.WriteLine("\nCPlayer::Skip"); int hr = 0; PropVariant var = new PropVariant(); try { hr = m_pMediaSession.Stop(); MFError.ThrowExceptionForHR(hr); hr = MFExtern.MFCreateSequencerSegmentOffset(SegmentID, 0, var); MFError.ThrowExceptionForHR(hr); hr = m_pMediaSession.Start(CLSID.MF_TIME_FORMAT_SEGMENT_OFFSET, var); MFError.ThrowExceptionForHR(hr); } catch (Exception e) { hr = Marshal.GetHRForException(e); } finally { var.Clear(); } return hr; }
//------------------------------------------------------------------- // Name: SendMarkerEvent // Description: Saned a marker event. // // pMarker: Pointer to our custom IMarker interface, which holds // the marker information. //------------------------------------------------------------------- void SendMarkerEvent(IMarker pMarker, FlushState fs) { int hrStatus = 0; // Status code for marker event. if (fs == FlushState.DropSamples) { hrStatus = E_Abort; } PropVariant var = new PropVariant(); // Get the context data. pMarker.GetContext(var); QueueEvent(MediaEventType.MEStreamSinkMarker, Guid.Empty, hrStatus, var); var.Clear(); }
////////////////////////////////////////////////////////////////////////// // Name: CPlayer::Invoke // Description: // Implementation of CAsyncCallback::Invoke. // Callback for asynchronous BeginGetEvent method. // Parameter: // pAsyncResult: Pointer to the result. // ///////////////////////////////////////////////////////////////////////// int IMFAsyncCallback.Invoke(IMFAsyncResult pAsyncResult) { MediaEventType eventType = MediaEventType.MEUnknown; IMFMediaEvent pEvent; PropVariant eventData = null; Exception excpt = null; int hr = S_Ok; try { int eventStatus = 0; // Event status eventData = new PropVariant(); // Event data // Get the event from the event queue. hr = m_pMediaSession.EndGetEvent(pAsyncResult, out pEvent); MFError.ThrowExceptionForHR(hr); // Get the event type. hr = pEvent.GetType(out eventType); MFError.ThrowExceptionForHR(hr); // Get the event data hr = pEvent.GetValue(eventData); MFError.ThrowExceptionForHR(hr); // Get the event status. If the operation that triggered the event // did not succeed, the status is a failure code. hr = pEvent.GetStatus(out eventStatus); MFError.ThrowExceptionForHR(hr); // Switch on the event type. Update the internal state of the CPlayer // as needed. switch (eventType) { // Session events case MediaEventType.MESessionStarted: { Debug.WriteLine(string.Format("{0}: MESessionStarted, Status: 0x{1:x}", eventType.ToString(), eventStatus)); m_State = PlayerState.Playing; PostMessage(m_hWnd, Form1.WM_NOTIFY_APP, new IntPtr((int)eventType), new IntPtr((int)m_State)); break; } case MediaEventType.MESessionPaused: { Debug.WriteLine(string.Format("{0}: MESessionPaused, Status: 0x{1:x}", eventType.ToString(), eventStatus)); m_State = PlayerState.Paused; PostMessage(m_hWnd, Form1.WM_NOTIFY_APP, new IntPtr((int)eventType), new IntPtr((int)m_State)); break; } case MediaEventType.MESessionStopped: { Debug.WriteLine(string.Format("{0}: MESessionStopped, Status: 0x{1:x}", eventType.ToString(), eventStatus)); m_State = PlayerState.Stopped; PostMessage(m_hWnd, Form1.WM_NOTIFY_APP, new IntPtr((int)eventType), new IntPtr((int)m_State)); break; } case MediaEventType.MESessionTopologyStatus: { Debug.WriteLine(string.Format("{0}: MESessionTopologyStatus, Status: 0x{1:x}", eventType.ToString(), eventStatus)); int value = 0; hr = pEvent.GetUINT32(MFAttributesClsid.MF_EVENT_TOPOLOGY_STATUS, out value); MFError.ThrowExceptionForHR(hr); int SegmentID = 0; long ID; //Get information about the new segment IMFTopology pTopology; pTopology = (IMFTopology)eventData.GetIUnknown(); try { hr = pTopology.GetTopologyID(out ID); MFError.ThrowExceptionForHR(hr); m_Segments.GetSegmentIDByTopoID(ID, out SegmentID); topostat.iTopologyStatusType = (MFTopoStatus)value; topostat.iSegmentId = SegmentID; switch (topostat.iTopologyStatusType) { case MFTopoStatus.StartedSource: m_ActiveSegment = SegmentID; break; case MFTopoStatus.Ended: m_ActiveSegment = -1; break; } GCHandle gc = GCHandle.Alloc(topostat); PostMessage(m_hWnd, Form1.WM_NOTIFY_APP, new IntPtr((int)MediaEventType.MESessionTopologyStatus), GCHandle.ToIntPtr(gc)); } finally { SafeRelease(pTopology); } break; } case MediaEventType.MENewPresentation: { Debug.WriteLine(string.Format("{0}: MENewPresentation, Status: 0x{1:x}", eventType.ToString(), eventStatus)); IMFPresentationDescriptor pPresentationDescriptor; int SegmentId = 0; pPresentationDescriptor = (IMFPresentationDescriptor)eventData.GetIUnknown(); try { //Queue the next segment on the media session QueueNextSegment(pPresentationDescriptor, out SegmentId); } finally { SafeRelease(pPresentationDescriptor); } PostMessage(m_hWnd, Form1.WM_NOTIFY_APP, new IntPtr((int)eventType), new IntPtr(SegmentId)); break; } case MediaEventType.MEEndOfPresentation: { Debug.WriteLine(string.Format("{0}: MEEndOfPresentation, Status: 0x{1:x}", eventType.ToString(), eventStatus)); int value = 0; try { hr = pEvent.GetUINT32(MFAttributesClsid.MF_EVENT_SOURCE_TOPOLOGY_CANCELED, out value); MFError.ThrowExceptionForHR(hr); } catch { } PostMessage(m_hWnd, Form1.WM_NOTIFY_APP, new IntPtr((int)eventType), new IntPtr(value)); break; } case MediaEventType.MEEndOfPresentationSegment: { Debug.WriteLine(string.Format("{0}: MEEndOfPresentationSegment, Status: 0x{1:x}", eventType.ToString(), eventStatus)); int value = 0; try { hr = pEvent.GetUINT32(MFAttributesClsid.MF_EVENT_SOURCE_TOPOLOGY_CANCELED, out value); MFError.ThrowExceptionForHR(hr); } catch { } PostMessage(m_hWnd, Form1.WM_NOTIFY_APP, new IntPtr((int)eventType), new IntPtr(value)); break; } case MediaEventType.MESessionNotifyPresentationTime: { Debug.WriteLine(string.Format("{0}: MESessionNotifyPresentationTime, Status: 0x{1:x}", eventType.ToString(), eventStatus)); HandleNotifyPresentationTime(pEvent); break; } case MediaEventType.MESessionClosed: { Debug.WriteLine(string.Format("{0}: MESessionClosed, Status: 0x{1:x}", eventType.ToString(), eventStatus)); m_hCloseEvent.Set(); break; } default: Debug.WriteLine(string.Format("{0}: Event", eventType.ToString())); break; } } catch (Exception e) { excpt = e; } finally { if (eventData != null) { eventData.Clear(); } } // Request another event. if (eventType != MediaEventType.MESessionClosed) { hr = m_pMediaSession.BeginGetEvent(this, null); MFError.ThrowExceptionForHR(hr); } if (excpt == null) { hr = S_Ok; } else { hr = Marshal.GetHRForException(excpt); } return hr; }
/////////////////////////////////////////////////////////////////////// // Name: Invoke // Description: Callback for asynchronous BeginGetEvent method. // // pAsyncResult: Pointer to the result. ///////////////////////////////////////////////////////////////////////// int IMFAsyncCallback.Invoke(IMFAsyncResult pAsyncResult) { // Make sure we *never* leave this entry point with an exception try { int hr; IMFMediaEvent pEvent; MediaEventType meType = MediaEventType.MEUnknown; // Event type PropVariant varEventData = new PropVariant(); // Event data // Get the event from the event queue. hr = m_pMEG.EndGetEvent(pAsyncResult, out pEvent); MFError.ThrowExceptionForHR(hr); // Get the event type. hr = pEvent.GetType(out meType); MFError.ThrowExceptionForHR(hr); // Get the event status. If the operation that triggered the event did // not succeed, the status is a failure code. hr = pEvent.GetStatus(out m_hrStatus); MFError.ThrowExceptionForHR(hr); if (m_hrStatus == 862022) // NS_S_DRM_MONITOR_CANCELLED { m_hrStatus = MFError.MF_E_OPERATION_CANCELLED; m_state = Enabler.Complete; } // Get the event data. hr = pEvent.GetValue(varEventData); MFError.ThrowExceptionForHR(hr); // For the MEEnablerCompleted action, notify the application. // Otherwise, request another event. Debug.WriteLine(string.Format("Content enabler event: {0}", meType.ToString())); if (meType == MediaEventType.MEEnablerCompleted) { PostMessage(m_hwnd, WM_APP_CONTENT_ENABLER, IntPtr.Zero, IntPtr.Zero); } else { if (meType == MediaEventType.MEEnablerProgress) { if (varEventData.GetVariantType() == PropVariant.VariantType.String) { Debug.WriteLine(string.Format("Progress: {0}", varEventData.GetString())); } } hr = m_pMEG.BeginGetEvent(this, null); MFError.ThrowExceptionForHR(hr); } // Clean up. varEventData.Clear(); SafeRelease(pEvent); return S_Ok; } catch (Exception e) { return Marshal.GetHRForException(e); } }
public void Copy(PropVariant pval) { if (pval == null) { throw new Exception("Null PropVariant sent to Copy"); } pval.Clear(); PropVariantCopy(pval, this); }
public IntPtr MarshalManagedToNative(object managedObj) { IntPtr p; // Cast the object back to a PropVariant m_prop = managedObj as PropVariant; if (m_prop != null) { // Release any memory currently allocated m_prop.Clear(); // Create an appropriately sized buffer, blank it, and send it to // the marshaler to make the COM call with. int iSize = GetNativeDataSize(); p = Marshal.AllocCoTaskMem(iSize); if (IntPtr.Size == 4) { Marshal.WriteInt64(p, 0); Marshal.WriteInt64(p, 8, 0); } else { Marshal.WriteInt64(p, 0); Marshal.WriteInt64(p, 8, 0); Marshal.WriteInt64(p, 16, 0); } } else { p = IntPtr.Zero; } return p; }
//------------------------------------------------------------------- // Name: Start // Description: Switches to running state. //------------------------------------------------------------------- public int Start( IMFPresentationDescriptor pPresentationDescriptor, Guid pguidTimeFormat, ConstPropVariant pvarStartPosition ) { // Make sure we *never* leave this entry point with an exception try { int hr; m_Log.WriteLine("-Start"); lock (this) { PropVariant var; long llStartOffset = 0; bool bIsSeek = false; bool bIsRestartFromCurrentPosition = false; // Fail if the source is shut down. CheckShutdown(); // Check parameters. // Start position and presentation descriptor cannot be null. if (pPresentationDescriptor == null) // pvarStartPosition == null || { throw new COMException("null presentation descriptor", E_InvalidArgument); } // Check the time format. Must be "reference time" units. if ((pguidTimeFormat != null) && (pguidTimeFormat != Guid.Empty)) { // Unrecognized time format GUID. throw new COMException("unrecognized time format guid", MFError.MF_E_UNSUPPORTED_TIME_FORMAT); } // Check the start position. if ((pvarStartPosition == null) || (pvarStartPosition.GetMFAttributeType() == MFAttributeType.None)) { // Start position is "current position". // For stopped, that means 0. Otherwise, use the current position. if (m_state == State.Stopped) { llStartOffset = 0; } else { llStartOffset = GetCurrentPosition(); bIsRestartFromCurrentPosition = true; } } else if (pvarStartPosition.GetMFAttributeType() == MFAttributeType.Uint64) { // Start position is given in pvarStartPosition in 100-ns units. llStartOffset = (long)pvarStartPosition; if (m_state != State.Stopped) { // Source is running or paused, so this is a seek. bIsSeek = true; } } else { // We don't support this time format. throw new COMException("We don't support this time format", MFError.MF_E_UNSUPPORTED_TIME_FORMAT); } // Validate the caller's presentation descriptor. ValidatePresentationDescriptor(pPresentationDescriptor); // Sends the MENewStream or MEUpdatedStream event. QueueNewStreamEvent(pPresentationDescriptor); // Notify the stream of the new start time. m_pStream.SetPosition(llStartOffset); // Send Started or Seeked events. We will send them // 1. from the media source // 2. from each stream var = new PropVariant(llStartOffset); // (1) Send the source event. if (bIsSeek) { QueueEvent(MediaEventType.MESourceSeeked, Guid.Empty, S_Ok, var); } else { // For starting, if we are RESTARTING from the current position and our // previous state was running/paused, then we need to add the // MF_EVENT_SOURCE_ACTUAL_START attribute to the event. This requires // creating the event object first. IMFMediaEvent pEvent = null; // Create the event. hr = MFExtern.MFCreateMediaEvent( MediaEventType.MESourceStarted, Guid.Empty, S_Ok, var, out pEvent ); MFError.ThrowExceptionForHR(hr); // For restarts, set the actual start time as an attribute. if (bIsRestartFromCurrentPosition) { hr = pEvent.SetUINT64(MFAttributesClsid.MF_EVENT_SOURCE_ACTUAL_START, llStartOffset); MFError.ThrowExceptionForHR(hr); } // Now queue the event. hr = m_pEventQueue.QueueEvent(pEvent); MFError.ThrowExceptionForHR(hr); //SAFE_RELEASE(pEvent); } // 2. Send the stream event. if (m_pStream != null) { if (bIsSeek) { m_pStream.QueueEvent(MediaEventType.MEStreamSeeked, Guid.Empty, S_Ok, var); } else { m_pStream.QueueEvent(MediaEventType.MEStreamStarted, Guid.Empty, S_Ok, var); } } // Update our state. m_state = State.Started; // NOTE: If this method were implemented as an asynchronous operation // and the operation Failed asynchronously, the media source would need // to send an MESourceStarted event with the failure code. For this // sample, all operations are synchronous (which is allowed), so any // failures are also synchronous. var.Clear(); } return S_Ok; } catch (Exception e) { return Marshal.GetHRForException(e); } }