auto* decoder = new WMFH264Decoder();
HRESULT hr = decoder->Init(cores); if (FAILED(hr)) {
CK_LOGE("Failed to initialize mDecoder!"); delete decoder; return nullptr;
}
returnnew VideoDecoder(aHost, decoder);
}
cdm::Status VideoDecoder::Decode(const cdm::InputBuffer_2& aInputBuffer,
cdm::VideoFrame* aVideoFrame) {
CK_LOGD("VideoDecoder::Decode"); // If the input buffer we have been passed has a null buffer, it means we // should drain. if (!aInputBuffer.data) { // This will drain the decoder until there are no frames left to drain, // whereupon it will return 'NeedsMoreData'.
CK_LOGD("VideoDecoder::Decode Input buffer null: Draining"); return Drain(aVideoFrame);
}
DecodeData* data = new DecodeData();
Assign(data->mBuffer, aInputBuffer.data, aInputBuffer.data_size);
data->mTimestamp = aInputBuffer.timestamp;
data->mCrypto = CryptoMetaData(&aInputBuffer);
AutoPtr<DecodeData> d(data);
HRESULT hr;
if (!data || !mDecoder) {
CK_LOGE("Decode job not set up correctly!"); return cdm::Status::kDecodeError;
}
std::vector<uint8_t>& buffer = data->mBuffer;
if (data->mCrypto.IsValid()) {
cdm::Status rv =
ClearKeyDecryptionManager::Get()->Decrypt(buffer, data->mCrypto);
if (STATUS_FAILED(rv)) {
CK_LOGARRAY("Failed to decrypt video using key ", aInputBuffer.key_id,
aInputBuffer.key_id_size); return rv;
}
}
// Read all the output from the decoder. Ideally, this would be a while loop // where we read the output and check the result as the condition. However, // this produces a memory leak connected to assigning a new CComPtr to the // address of the old one, which avoids the CComPtr cleaning up. while (true) {
CComPtr<IMFSample> output;
hr = mDecoder->Output(&output);
// If we don't have any inputs, we need more data. if (mOutputQueue.empty()) {
CK_LOGD("Decode failed. Not enought data; Requesting more input"); return cdm::Status::kNeedMoreData;
}
// We will get a MF_E_TRANSFORM_NEED_MORE_INPUT every time, as we always // consume everything in the buffer. if (hr != MF_E_TRANSFORM_NEED_MORE_INPUT && FAILED(hr)) {
CK_LOGD("Decode failed output ret=0x%x", hr); return cdm::Status::kDecodeError;
}
OutputData result = std::move(mOutputQueue.front());
mOutputQueue.pop();
// The Chromium CDM API doesn't have support for negative strides, though // they are theoretically possible in real world data. if (result.mStride <= 0) {
CK_LOGD("VideoDecoder::OutputFrame Failed! (negative stride)"); return cdm::Status::kDecodeError;
}
// Must convert to contiguous mediaBuffer to use IMD2DBuffer interface.
hr = aSample->ConvertToContiguousBuffer(&mediaBuffer);
ENSURE(SUCCEEDED(hr), hr);
// Try and use the IMF2DBuffer interface if available, otherwise fallback // to the IMFMediaBuffer interface. Apparently IMF2DBuffer is more efficient, // but only some systems (Windows 8?) support it.
BYTE* data = nullptr; LONG stride = 0;
CComPtr<IMF2DBuffer> twoDBuffer;
hr = mediaBuffer->QueryInterface(static_cast<IMF2DBuffer**>(&twoDBuffer)); if (SUCCEEDED(hr)) {
hr = twoDBuffer->Lock2D(&data, &stride);
ENSURE(SUCCEEDED(hr), hr);
} else {
hr = mediaBuffer->Lock(&data, nullptr, nullptr);
ENSURE(SUCCEEDED(hr), hr);
stride = aStride;
}
// WMF stores the U and V planes 16-row-aligned, so we need to add padding // to the row heights to ensure the source offsets of the Y'CbCr planes are // referenced properly. // YV12, planar format: [YYYY....][UUUU....][VVVV....] // i.e., Y, then U, then V.
uint32_t padding = 0; if (aFrameHeight % 16 != 0) {
padding = 16 - (aFrameHeight % 16);
}
uint32_t srcYSize = stride * (aFrameHeight + padding);
uint32_t srcUVSize = stride * (aFrameHeight + padding) / 4;
uint32_t halfStride = (stride + 1) / 2;
// Note: We allocate the minimal sized buffer required to send the // frame back over to the parent process. This is so that we request the // same sized frame as the buffer allocator expects.
using mozilla::CheckedUint32;
CheckedUint32 bufferSize = CheckedUint32(stride) * aPictureHeight +
((CheckedUint32(stride) * aPictureHeight) / 4) * 2;
// If the buffer is bigger than the max for a 32 bit, fail to avoid buffer // overflows. if (!bufferSize.isValid()) {
CK_LOGD("VideoDecoder::SampleToFrame Buffersize bigger than UINT32_MAX"); return E_FAIL;
}
// Get the buffer from the host.
cdm::Buffer* buffer = mHost->Allocate(bufferSize.value());
aVideoFrame->SetFrameBuffer(buffer);
// Make sure the buffer is non-null (allocate guarantees it will be of // sufficient size). if (!buffer) {
CK_LOGD("VideoDecoder::SampleToFrame Out of memory"); return E_OUTOFMEMORY;
}
uint8_t* outBuffer = buffer->Data();
aVideoFrame->SetPlaneOffset(cdm::kYPlane, 0);
// Offset of U plane is the size of the Y plane, excluding the padding that // WMF adds.
uint32_t dstUOffset = stride * aPictureHeight;
aVideoFrame->SetPlaneOffset(cdm::kUPlane, dstUOffset);
// Offset of the V plane is the size of the Y plane + the size of the U plane, // excluding any padding WMF adds.
uint32_t dstVOffset = stride * aPictureHeight + (stride * aPictureHeight) / 4;
aVideoFrame->SetPlaneOffset(cdm::kVPlane, dstVOffset);
// Release the reference we added in the constructor. There may be // WrapRefCounted tasks that also hold references to us, and keep // us alive a little longer.
Release();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.