blob: 18220d53015f591d6d9f4cd388a73973f0c4dabd [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/renderers/win/media_engine_notify_impl.h"
#include "media/base/win/mf_helpers.h"
namespace media {
namespace {
#define ENUM_TO_STRING(enum) \
case enum: \
return #enum
std::string MediaEngineEventToString(MF_MEDIA_ENGINE_EVENT event) {
switch (event) {
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_LOADSTART);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_PROGRESS);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_SUSPEND);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_ABORT);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_ERROR);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_EMPTIED);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_STALLED);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_PLAY);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_PAUSE);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_LOADEDDATA);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_WAITING);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_PLAYING);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_CANPLAY);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_CANPLAYTHROUGH);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_SEEKING);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_SEEKED);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_TIMEUPDATE);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_ENDED);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_RATECHANGE);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_FORMATCHANGE);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_TIMELINE_MARKER);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_BALANCECHANGE);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_DOWNLOADCOMPLETE);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_FRAMESTEPCOMPLETED);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_NOTIFYSTABLESTATE);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_TRACKSCHANGE);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_OPMINFO);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_RESOURCELOST);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_DELAYLOADEVENT_CHANGED);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_STREAMRENDERINGERROR);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_SUPPORTEDRATES_CHANGED);
ENUM_TO_STRING(MF_MEDIA_ENGINE_EVENT_AUDIOENDPOINTCHANGE);
default:
return "Unknown MF_MEDIA_ENGINE_EVENT";
}
}
#undef ENUM_TO_STRING
PipelineStatus MediaEngineErrorToPipelineStatus(
MF_MEDIA_ENGINE_ERR media_engine_error,
HRESULT hr) {
// HRESULT 0x8004CD12 is DRM_E_TEE_INVALID_HWDRM_STATE, which can happen
// during OS sleep/resume, or moving video to different graphics adapters.
// This is not an error, so special case it here.
if (hr == static_cast<HRESULT>(0x8004CD12))
return PipelineStatus::PIPELINE_ERROR_HARDWARE_CONTEXT_RESET;
switch (media_engine_error) {
case MF_MEDIA_ENGINE_ERR_NOERROR:
return PipelineStatus::PIPELINE_OK;
case MF_MEDIA_ENGINE_ERR_ABORTED:
return PipelineStatus::PIPELINE_ERROR_ABORT;
case MF_MEDIA_ENGINE_ERR_NETWORK:
return PipelineStatus::PIPELINE_ERROR_NETWORK;
case MF_MEDIA_ENGINE_ERR_DECODE:
FALLTHROUGH;
case MF_MEDIA_ENGINE_ERR_ENCRYPTED:
return PipelineStatus::PIPELINE_ERROR_DECODE;
case MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED:
return PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN;
default:
NOTREACHED();
return PipelineStatus::PIPELINE_ERROR_INVALID_STATE;
}
}
} // namespace
MediaEngineNotifyImpl::MediaEngineNotifyImpl() = default;
MediaEngineNotifyImpl::~MediaEngineNotifyImpl() = default;
HRESULT MediaEngineNotifyImpl::RuntimeClassInitialize(
ErrorCB error_cb,
EndedCB ended_cb,
BufferingStateChangedCB buffering_state_changed_cb,
VideoNaturalSizeChangedCB video_natural_size_changed_cb,
TimeUpdateCB time_update_cb) {
DVLOG_FUNC(1);
error_cb_ = std::move(error_cb);
ended_cb_ = std::move(ended_cb);
buffering_state_changed_cb_ = std::move(buffering_state_changed_cb);
video_natural_size_changed_cb_ = std::move(video_natural_size_changed_cb);
time_update_cb_ = std::move(time_update_cb);
return S_OK;
}
// |param1| and |param2|'s meaning depends on the |event_code| from
// https://docs.microsoft.com/en-us/windows/win32/api/mfmediaengine/ne-mfmediaengine-mf_media_engine_event
// This method always return S_OK. Even for error |event_code| because we
// successfully handled the event.
HRESULT MediaEngineNotifyImpl::EventNotify(DWORD event_code,
DWORD_PTR param1,
DWORD param2) {
auto event = static_cast<MF_MEDIA_ENGINE_EVENT>(event_code);
DVLOG_FUNC(3) << "event=" << MediaEngineEventToString(event);
base::AutoLock lock(lock_);
if (has_shutdown_)
return S_OK;
switch (event) {
case MF_MEDIA_ENGINE_EVENT_ERROR: {
// |param1| - A member of the MF_MEDIA_ENGINE_ERR enumeration.
// |param2| - An HRESULT error code, or zero.
MF_MEDIA_ENGINE_ERR error = static_cast<MF_MEDIA_ENGINE_ERR>(param1);
HRESULT hr = param2;
LOG(ERROR) << __func__ << ": error=" << error << ", hr=" << PrintHr(hr);
error_cb_.Run(MediaEngineErrorToPipelineStatus(error, hr), hr);
break;
}
case MF_MEDIA_ENGINE_EVENT_ENDED:
ended_cb_.Run();
break;
case MF_MEDIA_ENGINE_EVENT_FORMATCHANGE:
video_natural_size_changed_cb_.Run();
break;
case MF_MEDIA_ENGINE_EVENT_LOADEDDATA:
video_natural_size_changed_cb_.Run();
FALLTHROUGH;
case MF_MEDIA_ENGINE_EVENT_PLAYING:
buffering_state_changed_cb_.Run(
BufferingState::BUFFERING_HAVE_ENOUGH,
BufferingStateChangeReason::BUFFERING_CHANGE_REASON_UNKNOWN);
break;
case MF_MEDIA_ENGINE_EVENT_WAITING:
buffering_state_changed_cb_.Run(
BufferingState::BUFFERING_HAVE_NOTHING,
BufferingStateChangeReason::BUFFERING_CHANGE_REASON_UNKNOWN);
break;
case MF_MEDIA_ENGINE_EVENT_TIMEUPDATE:
time_update_cb_.Run();
break;
default:
DVLOG_FUNC(2) << "Unhandled event=" << MediaEngineEventToString(event);
break;
}
return S_OK;
}
void MediaEngineNotifyImpl::Shutdown() {
DVLOG_FUNC(1);
base::AutoLock lock(lock_);
has_shutdown_ = true;
}
} // namespace media