content/media/directshow/DirectShowUtils.cpp

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

     1 /* vim:set ts=2 sw=2 sts=2 et cindent: */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "dshow.h"
     7 #include "dmodshow.h"
     8 #include "wmcodecdsp.h"
     9 #include "dmoreg.h"
    10 #include "DirectShowUtils.h"
    11 #include "nsAutoPtr.h"
    12 #include "mozilla/ArrayUtils.h"
    13 #include "mozilla/RefPtr.h"
    15 namespace mozilla {
    17 #if defined(PR_LOGGING)
    19 // Create a table which maps GUIDs to a string representation of the GUID.
    20 // This is useful for debugging purposes, for logging the GUIDs of media types.
    21 // This is only available when logging is enabled, i.e. not in release builds.
    22 struct GuidToName {
    23   const char* name;
    24   const GUID guid;
    25 };
    27 #pragma push_macro("OUR_GUID_ENTRY")
    28 #undef OUR_GUID_ENTRY
    29 #define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
    30 { #name, {l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8} },
    32 static const GuidToName GuidToNameTable[] = {
    33 #include <uuids.h>
    34 };
    36 #pragma pop_macro("OUR_GUID_ENTRY")
    38 const char*
    39 GetDirectShowGuidName(const GUID& aGuid)
    40 {
    41   const size_t len = ArrayLength(GuidToNameTable);
    42   for (unsigned i = 0; i < len; i++) {
    43     if (IsEqualGUID(aGuid, GuidToNameTable[i].guid)) {
    44       return GuidToNameTable[i].name;
    45     }
    46   }
    47   return "Unknown";
    48 }
    49 #endif // PR_LOGGING
    51 void
    52 RemoveGraphFromRunningObjectTable(DWORD aRotRegister)
    53 {
    54   nsRefPtr<IRunningObjectTable> runningObjectTable;
    55   if (SUCCEEDED(GetRunningObjectTable(0, getter_AddRefs(runningObjectTable)))) {
    56     runningObjectTable->Revoke(aRotRegister);
    57   }
    58 }
    60 HRESULT
    61 AddGraphToRunningObjectTable(IUnknown *aUnkGraph, DWORD *aOutRotRegister)
    62 {
    63   HRESULT hr;
    65   nsRefPtr<IMoniker> moniker;
    66   nsRefPtr<IRunningObjectTable> runningObjectTable;
    68   hr = GetRunningObjectTable(0, getter_AddRefs(runningObjectTable));
    69   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    71   const size_t STRING_LENGTH = 256;
    72   WCHAR wsz[STRING_LENGTH];
    74   StringCchPrintfW(wsz,
    75                    STRING_LENGTH,
    76                    L"FilterGraph %08x pid %08x",
    77                    (DWORD_PTR)aUnkGraph,
    78                    GetCurrentProcessId());
    80   hr = CreateItemMoniker(L"!", wsz, getter_AddRefs(moniker));
    81   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    83   hr = runningObjectTable->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE,
    84                                     aUnkGraph,
    85                                     moniker,
    86                                     aOutRotRegister);
    87   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    89   return S_OK;
    90 }
    92 const char*
    93 GetGraphNotifyString(long evCode)
    94 {
    95 #define CASE(x) case x: return #x
    96   switch(evCode) {
    97     CASE(EC_ACTIVATE); // A video window is being activated or deactivated.
    98     CASE(EC_BANDWIDTHCHANGE); // Not supported.
    99     CASE(EC_BUFFERING_DATA); // The graph is buffering data, or has stopped buffering data.
   100     CASE(EC_BUILT); // Send by the Video Control when a graph has been built. Not forwarded to applications.
   101     CASE(EC_CLOCK_CHANGED); // The reference clock has changed.
   102     CASE(EC_CLOCK_UNSET); // The clock provider was disconnected.
   103     CASE(EC_CODECAPI_EVENT); // Sent by an encoder to signal an encoding event.
   104     CASE(EC_COMPLETE); // All data from a particular stream has been rendered.
   105     CASE(EC_CONTENTPROPERTY_CHANGED); // Not supported.
   106     CASE(EC_DEVICE_LOST); // A Plug and Play device was removed or has become available again.
   107     CASE(EC_DISPLAY_CHANGED); // The display mode has changed.
   108     CASE(EC_END_OF_SEGMENT); // The end of a segment has been reached.
   109     CASE(EC_EOS_SOON); // Not supported.
   110     CASE(EC_ERROR_STILLPLAYING); // An asynchronous command to run the graph has failed.
   111     CASE(EC_ERRORABORT); // An operation was aborted because of an error.
   112     CASE(EC_ERRORABORTEX); // An operation was aborted because of an error.
   113     CASE(EC_EXTDEVICE_MODE_CHANGE); // Not supported.
   114     CASE(EC_FILE_CLOSED); // The source file was closed because of an unexpected event.
   115     CASE(EC_FULLSCREEN_LOST); // The video renderer is switching out of full-screen mode.
   116     CASE(EC_GRAPH_CHANGED); // The filter graph has changed.
   117     CASE(EC_LENGTH_CHANGED); // The length of a source has changed.
   118     CASE(EC_LOADSTATUS); // Notifies the application of progress when opening a network file.
   119     CASE(EC_MARKER_HIT); // Not supported.
   120     CASE(EC_NEED_RESTART); // A filter is requesting that the graph be restarted.
   121     CASE(EC_NEW_PIN); // Not supported.
   122     CASE(EC_NOTIFY_WINDOW); // Notifies a filter of the video renderer's window.
   123     CASE(EC_OLE_EVENT); // A filter is passing a text string to the application.
   124     CASE(EC_OPENING_FILE); // The graph is opening a file, or has finished opening a file.
   125     CASE(EC_PALETTE_CHANGED); // The video palette has changed.
   126     CASE(EC_PAUSED); // A pause request has completed.
   127     CASE(EC_PLEASE_REOPEN); // The source file has changed.
   128     CASE(EC_PREPROCESS_COMPLETE); // Sent by the WM ASF Writer filter when it completes the pre-processing for multipass encoding.
   129     CASE(EC_PROCESSING_LATENCY); // Indicates the amount of time that a component is taking to process each sample.
   130     CASE(EC_QUALITY_CHANGE); // The graph is dropping samples, for quality control.
   131     //CASE(EC_RENDER_FINISHED); // Not supported.
   132     CASE(EC_REPAINT); // A video renderer requires a repaint.
   133     CASE(EC_SAMPLE_LATENCY); // Specifies how far behind schedule a component is for processing samples.
   134     //CASE(EC_SAMPLE_NEEDED); // Requests a new input sample from the Enhanced Video Renderer (EVR) filter.
   135     CASE(EC_SCRUB_TIME); // Specifies the time stamp for the most recent frame step.
   136     CASE(EC_SEGMENT_STARTED); // A new segment has started.
   137     CASE(EC_SHUTTING_DOWN); // The filter graph is shutting down, prior to being destroyed.
   138     CASE(EC_SNDDEV_IN_ERROR); // A device error has occurred in an audio capture filter.
   139     CASE(EC_SNDDEV_OUT_ERROR); // A device error has occurred in an audio renderer filter.
   140     CASE(EC_STARVATION); // A filter is not receiving enough data.
   141     CASE(EC_STATE_CHANGE); // The filter graph has changed state.
   142     CASE(EC_STATUS); // Contains two arbitrary status strings.
   143     CASE(EC_STEP_COMPLETE); // A filter performing frame stepping has stepped the specified number of frames.
   144     CASE(EC_STREAM_CONTROL_STARTED); // A stream-control start command has taken effect.
   145     CASE(EC_STREAM_CONTROL_STOPPED); // A stream-control stop command has taken effect.
   146     CASE(EC_STREAM_ERROR_STILLPLAYING); // An error has occurred in a stream. The stream is still playing.
   147     CASE(EC_STREAM_ERROR_STOPPED); // A stream has stopped because of an error.
   148     CASE(EC_TIMECODE_AVAILABLE); // Not supported.
   149     CASE(EC_UNBUILT); // Send by the Video Control when a graph has been torn down. Not forwarded to applications.
   150     CASE(EC_USERABORT); // The user has terminated playback.
   151     CASE(EC_VIDEO_SIZE_CHANGED); // The native video size has changed.
   152     CASE(EC_VIDEOFRAMEREADY); // A video frame is ready for display.
   153     CASE(EC_VMR_RECONNECTION_FAILED); // Sent by the VMR-7 and the VMR-9 when it was unable to accept a dynamic format change request from the upstream decoder.
   154     CASE(EC_VMR_RENDERDEVICE_SET); // Sent when the VMR has selected its rendering mechanism.
   155     CASE(EC_VMR_SURFACE_FLIPPED); // Sent when the VMR-7's allocator presenter has called the DirectDraw Flip method on the surface being presented.
   156     CASE(EC_WINDOW_DESTROYED); // The video renderer was destroyed or removed from the graph.
   157     CASE(EC_WMT_EVENT); // Sent by the WM ASF Reader filter when it reads ASF files protected by digital rights management (DRM).
   158     CASE(EC_WMT_INDEX_EVENT); // Sent when an application uses the WM ASF Writer to index Windows Media Video files.
   159     CASE(S_OK); // Success.
   160     CASE(VFW_S_AUDIO_NOT_RENDERED); // Partial success; the audio was not rendered.
   161     CASE(VFW_S_DUPLICATE_NAME); // Success; the Filter Graph Manager modified a filter name to avoid duplication.
   162     CASE(VFW_S_PARTIAL_RENDER); // Partial success; some of the streams in this movie are in an unsupported format.
   163     CASE(VFW_S_VIDEO_NOT_RENDERED); // Partial success; the video was not rendered.
   164     CASE(E_ABORT); // Operation aborted.
   165     CASE(E_OUTOFMEMORY); // Insufficient memory.
   166     CASE(E_POINTER); // Null pointer argument.
   167     CASE(VFW_E_CANNOT_CONNECT); // No combination of intermediate filters could be found to make the connection.
   168     CASE(VFW_E_CANNOT_RENDER); // No combination of filters could be found to render the stream.
   169     CASE(VFW_E_NO_ACCEPTABLE_TYPES); // There is no common media type between these pins.
   170     CASE(VFW_E_NOT_IN_GRAPH);
   172     default:
   173       return "Unknown Code";
   174   };
   175 #undef CASE
   176 }
   178 HRESULT
   179 CreateAndAddFilter(IGraphBuilder* aGraph,
   180                    REFGUID aFilterClsId,
   181                    LPCWSTR aFilterName,
   182                    IBaseFilter **aOutFilter)
   183 {
   184   NS_ENSURE_TRUE(aGraph, E_POINTER);
   185   NS_ENSURE_TRUE(aOutFilter, E_POINTER);
   186   HRESULT hr;
   188   nsRefPtr<IBaseFilter> filter;
   189   hr = CoCreateInstance(aFilterClsId,
   190                         nullptr,
   191                         CLSCTX_INPROC_SERVER,
   192                         IID_IBaseFilter,
   193                         getter_AddRefs(filter));
   194   if (FAILED(hr)) {
   195     // Object probably not available on this system.
   196     return hr;
   197   }
   199   hr = aGraph->AddFilter(filter, aFilterName);
   200   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   202   filter.forget(aOutFilter);
   204   return S_OK;
   205 }
   207 HRESULT
   208 AddMP3DMOWrapperFilter(IGraphBuilder* aGraph,
   209                        IBaseFilter **aOutFilter)
   210 {
   211   NS_ENSURE_TRUE(aGraph, E_POINTER);
   212   NS_ENSURE_TRUE(aOutFilter, E_POINTER);
   213   HRESULT hr;
   215   // Create the wrapper filter.
   216   nsRefPtr<IBaseFilter> filter;
   217   hr = CoCreateInstance(CLSID_DMOWrapperFilter,
   218                         nullptr,
   219                         CLSCTX_INPROC_SERVER,
   220                         IID_IBaseFilter,
   221                         getter_AddRefs(filter));
   222   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   224   // Query for IDMOWrapperFilter.
   225   nsRefPtr<IDMOWrapperFilter> dmoWrapper;
   226   hr = filter->QueryInterface(IID_IDMOWrapperFilter,
   227                               getter_AddRefs(dmoWrapper));
   228   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   230   hr = dmoWrapper->Init(CLSID_CMP3DecMediaObject, DMOCATEGORY_AUDIO_DECODER);
   231   if (FAILED(hr)) {
   232     // Can't instantiate MP3 DMO. It doesn't exist on Windows XP, we're
   233     // probably hitting that. Don't log warning to console, this is an
   234     // expected error.
   235     return hr;
   236   }
   238   // Add the wrapper filter to graph.
   239   hr = aGraph->AddFilter(filter, L"MP3 Decoder DMO");
   240   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   242   filter.forget(aOutFilter);
   244   return S_OK;
   245 }
   247 // Match a pin by pin direction and connection state.
   248 HRESULT
   249 MatchUnconnectedPin(IPin* aPin,
   250                     PIN_DIRECTION aPinDir,
   251                     bool *aOutMatches)
   252 {
   253   NS_ENSURE_TRUE(aPin, E_POINTER);
   254   NS_ENSURE_TRUE(aOutMatches, E_POINTER);
   256   // Ensure the pin is unconnected.
   257   RefPtr<IPin> peer;
   258   HRESULT hr = aPin->ConnectedTo(byRef(peer));
   259   if (hr != VFW_E_NOT_CONNECTED) {
   260     *aOutMatches = false;
   261     return hr;
   262   }
   264   // Ensure the pin is of the specified direction.
   265   PIN_DIRECTION pinDir;
   266   hr = aPin->QueryDirection(&pinDir);
   267   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   269   *aOutMatches = (pinDir == aPinDir);
   270   return S_OK;
   271 }
   273 // Return the first unconnected input pin or output pin.
   274 TemporaryRef<IPin>
   275 GetUnconnectedPin(IBaseFilter* aFilter, PIN_DIRECTION aPinDir)
   276 {
   277   RefPtr<IEnumPins> enumPins;
   279   HRESULT hr = aFilter->EnumPins(byRef(enumPins));
   280   NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
   282   // Test each pin to see if it matches the direction we're looking for.
   283   RefPtr<IPin> pin;
   284   while (S_OK == enumPins->Next(1, byRef(pin), nullptr)) {
   285     bool matches = FALSE;
   286     if (SUCCEEDED(MatchUnconnectedPin(pin, aPinDir, &matches)) &&
   287         matches) {
   288       return pin;
   289     }
   290   }
   292   return nullptr;
   293 }
   295 HRESULT
   296 ConnectFilters(IGraphBuilder* aGraph,
   297                IBaseFilter* aOutputFilter,
   298                IBaseFilter* aInputFilter)
   299 {
   300   RefPtr<IPin> output = GetUnconnectedPin(aOutputFilter, PINDIR_OUTPUT);
   301   NS_ENSURE_TRUE(output, E_FAIL);
   303   RefPtr<IPin> input = GetUnconnectedPin(aInputFilter, PINDIR_INPUT);
   304   NS_ENSURE_TRUE(output, E_FAIL);
   306   return aGraph->Connect(output, input);
   307 }
   309 } // namespace mozilla

mercurial