1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "media/renderers/win/media_engine_notify_impl.h"
6 
7 #include "media/base/win/mf_helpers.h"
8 
9 namespace media {
10 
11 namespace {
12 
13 #define ENUM_TO_STRING(enum) \
14   case enum:                 \
15     return #enum
16 
MediaEngineEventToString(MF_MEDIA_ENGINE_EVENT event)17 std::string MediaEngineEventToString(MF_MEDIA_ENGINE_EVENT event) {
18   switch (event) {
19     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_LOADSTART);
20     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_PROGRESS);
21     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_SUSPEND);
22     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_ABORT);
23     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_ERROR);
24     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_EMPTIED);
25     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_STALLED);
26     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_PLAY);
27     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_PAUSE);
28     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA);
29     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_LOADEDDATA);
30     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_WAITING);
31     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_PLAYING);
32     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_CANPLAY);
33     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_CANPLAYTHROUGH);
34     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_SEEKING);
35     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_SEEKED);
36     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_TIMEUPDATE);
37     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_ENDED);
38     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_RATECHANGE);
39     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE);
40     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE);
41     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_FORMATCHANGE);
42     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS);
43     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_TIMELINE_MARKER);
44     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_BALANCECHANGE);
45     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_DOWNLOADCOMPLETE);
46     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED);
47     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED);
48     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_FRAMESTEPCOMPLETED);
49     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_NOTIFYSTABLESTATE);
50     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY);
51     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_TRACKSCHANGE);
52     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_OPMINFO);
53     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_RESOURCELOST);
54     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_DELAYLOADEVENT_CHANGED);
55     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_STREAMRENDERINGERROR);
56     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_SUPPORTEDRATES_CHANGED);
57     ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_AUDIOENDPOINTCHANGE);
58     default:
59       return "Unknown MF_MEDIA_ENGINE_EVENT";
60   }
61 }
62 
63 #undef ENUM_TO_STRING
64 
MediaEngineStatusToPipelineStatus(MF_MEDIA_ENGINE_ERR media_engine_status)65 PipelineStatus MediaEngineStatusToPipelineStatus(
66     MF_MEDIA_ENGINE_ERR media_engine_status) {
67   switch (media_engine_status) {
68     case MF_MEDIA_ENGINE_ERR_NOERROR:
69       return PipelineStatus::PIPELINE_OK;
70     case MF_MEDIA_ENGINE_ERR_ABORTED:
71       return PipelineStatus::PIPELINE_ERROR_ABORT;
72     case MF_MEDIA_ENGINE_ERR_NETWORK:
73       return PipelineStatus::PIPELINE_ERROR_NETWORK;
74     case MF_MEDIA_ENGINE_ERR_DECODE:
75       FALLTHROUGH;
76     case MF_MEDIA_ENGINE_ERR_ENCRYPTED:
77       return PipelineStatus::PIPELINE_ERROR_DECODE;
78     case MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED:
79       return PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN;
80     default:
81       NOTREACHED();
82       return PipelineStatus::PIPELINE_ERROR_INVALID_STATE;
83   }
84 }
85 
86 }  // namespace
87 
88 MediaEngineNotifyImpl::MediaEngineNotifyImpl() = default;
89 MediaEngineNotifyImpl::~MediaEngineNotifyImpl() = default;
90 
RuntimeClassInitialize(ErrorCB error_cb,EndedCB ended_cb,BufferingStateChangedCB buffering_state_changed_cb,VideoNaturalSizeChangedCB video_natural_size_changed_cb,TimeUpdateCB time_update_cb)91 HRESULT MediaEngineNotifyImpl::RuntimeClassInitialize(
92     ErrorCB error_cb,
93     EndedCB ended_cb,
94     BufferingStateChangedCB buffering_state_changed_cb,
95     VideoNaturalSizeChangedCB video_natural_size_changed_cb,
96     TimeUpdateCB time_update_cb) {
97   DVLOG_FUNC(1);
98 
99   error_cb_ = std::move(error_cb);
100   ended_cb_ = std::move(ended_cb);
101   buffering_state_changed_cb_ = std::move(buffering_state_changed_cb);
102   video_natural_size_changed_cb_ = std::move(video_natural_size_changed_cb);
103   time_update_cb_ = std::move(time_update_cb);
104   return S_OK;
105 }
106 
107 // |param1| and |param2|'s meaning depends on the |event_code| from
108 // https://docs.microsoft.com/en-us/windows/win32/api/mfmediaengine/ne-mfmediaengine-mf_media_engine_event
109 // This method always return S_OK. Even for error |event_code| because we
110 // successfully handled the event.
EventNotify(DWORD event_code,DWORD_PTR param1,DWORD param2)111 HRESULT MediaEngineNotifyImpl::EventNotify(DWORD event_code,
112                                            DWORD_PTR param1,
113                                            DWORD param2) {
114   auto event = static_cast<MF_MEDIA_ENGINE_EVENT>(event_code);
115   DVLOG_FUNC(3) << "event=" << MediaEngineEventToString(event);
116 
117   base::AutoLock lock(lock_);
118   if (has_shutdown_)
119     return S_OK;
120 
121   switch (event) {
122     case MF_MEDIA_ENGINE_EVENT_ERROR: {
123       // |param1| - A member of the MF_MEDIA_ENGINE_ERR enumeration.
124       // |param2| - An HRESULT error code, or zero.
125       MF_MEDIA_ENGINE_ERR error = static_cast<MF_MEDIA_ENGINE_ERR>(param1);
126       LOG(ERROR) << __func__ << ": error=" << error
127                  << ", hr=" << PrintHr(param2);
128       error_cb_.Run(MediaEngineStatusToPipelineStatus(error));
129       break;
130     }
131     case MF_MEDIA_ENGINE_EVENT_ENDED:
132       ended_cb_.Run();
133       break;
134     case MF_MEDIA_ENGINE_EVENT_FORMATCHANGE:
135       video_natural_size_changed_cb_.Run();
136       break;
137     case MF_MEDIA_ENGINE_EVENT_LOADEDDATA:
138       video_natural_size_changed_cb_.Run();
139       FALLTHROUGH;
140     case MF_MEDIA_ENGINE_EVENT_PLAYING:
141       buffering_state_changed_cb_.Run(
142           BufferingState::BUFFERING_HAVE_ENOUGH,
143           BufferingStateChangeReason::BUFFERING_CHANGE_REASON_UNKNOWN);
144       break;
145     case MF_MEDIA_ENGINE_EVENT_WAITING:
146       buffering_state_changed_cb_.Run(
147           BufferingState::BUFFERING_HAVE_NOTHING,
148           BufferingStateChangeReason::BUFFERING_CHANGE_REASON_UNKNOWN);
149       break;
150     case MF_MEDIA_ENGINE_EVENT_TIMEUPDATE:
151       time_update_cb_.Run();
152       break;
153 
154     default:
155       DVLOG_FUNC(2) << "Unhandled event=" << MediaEngineEventToString(event);
156       break;
157   }
158   return S_OK;
159 }
160 
Shutdown()161 void MediaEngineNotifyImpl::Shutdown() {
162   DVLOG_FUNC(1);
163 
164   base::AutoLock lock(lock_);
165   has_shutdown_ = true;
166 }
167 
168 }  // namespace media
169