blob: bffb29488d31fdf064579fe3db67826bd948fb68 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef CODEC_BASE_H_
#define CODEC_BASE_H_
#include <list>
#include <memory>
#include <stdint.h>
#define STRINGIFY_ENUMS
#include <media/hardware/CryptoAPI.h>
#include <media/hardware/HardwareAPI.h>
#include <media/MediaCodecInfo.h>
#include <media/stagefright/foundation/AHandler.h>
#include <media/stagefright/foundation/ColorUtils.h>
#include <media/stagefright/MediaErrors.h>
#include <system/graphics.h>
#include <utils/NativeHandle.h>
class C2Buffer;
namespace android {
class BufferChannelBase;
struct BufferProducerWrapper;
class MediaCodecBuffer;
struct PersistentSurface;
class RenderedFrameInfo;
class Surface;
struct ICrypto;
class IMemory;
namespace hardware {
class HidlMemory;
namespace cas {
namespace native {
namespace V1_0 {
struct IDescrambler;
}}}
namespace drm {
namespace V1_0 {
struct SharedBuffer;
}}
}
using hardware::cas::native::V1_0::IDescrambler;
struct AccessUnitInfo {
uint32_t mFlags;
uint32_t mSize;
int64_t mTimestamp;
AccessUnitInfo(uint32_t flags, uint32_t size, int64_t ptsUs)
:mFlags(flags), mSize(size), mTimestamp(ptsUs) {
}
~AccessUnitInfo() {}
};
struct CodecCryptoInfo {
size_t mNumSubSamples{0};
CryptoPlugin::SubSample *mSubSamples{nullptr};
uint8_t *mIv{nullptr};
uint8_t *mKey{nullptr};
enum CryptoPlugin::Mode mMode;
CryptoPlugin::Pattern mPattern;
virtual ~CodecCryptoInfo() {}
protected:
CodecCryptoInfo():
mNumSubSamples(0),
mSubSamples(nullptr),
mIv(nullptr),
mKey(nullptr),
mMode{CryptoPlugin::kMode_Unencrypted},
mPattern{0, 0} {
}
};
struct CodecParameterDescriptor {
std::string name;
AMessage::Type type;
};
struct CodecBase : public AHandler, /* static */ ColorUtils {
/**
* This interface defines events firing from CodecBase back to MediaCodec.
* All methods must not block.
*/
class CodecCallback {
public:
virtual ~CodecCallback() = default;
/**
* Notify MediaCodec for seeing an output EOS.
*
* @param err the underlying cause of the EOS. If the value is neither
* OK nor ERROR_END_OF_STREAM, the EOS is declared
* prematurely for that error.
*/
virtual void onEos(status_t err) = 0;
/**
* Notify MediaCodec that start operation is complete.
*/
virtual void onStartCompleted() = 0;
/**
* Notify MediaCodec that stop operation is complete.
*/
virtual void onStopCompleted() = 0;
/**
* Notify MediaCodec that release operation is complete.
*/
virtual void onReleaseCompleted() = 0;
/**
* Notify MediaCodec that flush operation is complete.
*/
virtual void onFlushCompleted() = 0;
/**
* Notify MediaCodec that an error is occurred.
*
* @param err an error code for the occurred error.
* @param actionCode an action code for severity of the error.
*/
virtual void onError(status_t err, enum ActionCode actionCode) = 0;
/**
* Notify MediaCodec that the underlying component is allocated.
*
* @param componentName the unique name of the component specified in
* MediaCodecList.
*/
virtual void onComponentAllocated(const char *componentName) = 0;
/**
* Notify MediaCodec that the underlying component is configured.
*
* @param inputFormat an input format at configure time.
* @param outputFormat an output format at configure time.
*/
virtual void onComponentConfigured(
const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) = 0;
/**
* Notify MediaCodec that the input surface is created.
*
* @param inputFormat an input format at surface creation. Formats
* could change from the previous state as a result
* of creating a surface.
* @param outputFormat an output format at surface creation.
* @param inputSurface the created surface.
*/
virtual void onInputSurfaceCreated(
const sp<AMessage> &inputFormat,
const sp<AMessage> &outputFormat,
const sp<BufferProducerWrapper> &inputSurface) = 0;
/**
* Notify MediaCodec that the input surface creation is failed.
*
* @param err an error code of the cause.
*/
virtual void onInputSurfaceCreationFailed(status_t err) = 0;
/**
* Notify MediaCodec that the component accepted the provided input
* surface.
*
* @param inputFormat an input format at surface assignment. Formats
* could change from the previous state as a result
* of assigning a surface.
* @param outputFormat an output format at surface assignment.
*/
virtual void onInputSurfaceAccepted(
const sp<AMessage> &inputFormat,
const sp<AMessage> &outputFormat) = 0;
/**
* Notify MediaCodec that the component declined the provided input
* surface.
*
* @param err an error code of the cause.
*/
virtual void onInputSurfaceDeclined(status_t err) = 0;
/**
* Noitfy MediaCodec that the requested input EOS is sent to the input
* surface.
*
* @param err an error code returned from the surface. If there is no
* input surface, the value is INVALID_OPERATION.
*/
virtual void onSignaledInputEOS(status_t err) = 0;
/**
* Notify MediaCodec that output frames are rendered with information on
* those frames.
*
* @param done a list of rendered frames.
*/
virtual void onOutputFramesRendered(const std::list<RenderedFrameInfo> &done) = 0;
/**
* Notify MediaCodec that output buffers are changed.
*/
virtual void onOutputBuffersChanged() = 0;
/**
* Notify MediaCodec that the first tunnel frame is ready.
*/
virtual void onFirstTunnelFrameReady() = 0;
/**
* Notify MediaCodec that there are metrics to be updated.
*
* @param updatedMetrics metrics need to be updated.
*/
virtual void onMetricsUpdated(const sp<AMessage> &updatedMetrics) = 0;
};
/**
* This interface defines events firing from BufferChannelBase back to MediaCodec.
* All methods must not block.
*/
class BufferCallback {
public:
virtual ~BufferCallback() = default;
/**
* Notify MediaCodec that an input buffer is available with given index.
* When BufferChannelBase::getInputBufferArray() is not called,
* BufferChannelBase may report different buffers with the same index if
* MediaCodec already queued/discarded the buffer. After calling
* BufferChannelBase::getInputBufferArray(), the buffer and index match the
* returned array.
*/
virtual void onInputBufferAvailable(
size_t index, const sp<MediaCodecBuffer> &buffer) = 0;
/**
* Notify MediaCodec that an output buffer is available with given index.
* When BufferChannelBase::getOutputBufferArray() is not called,
* BufferChannelBase may report different buffers with the same index if
* MediaCodec already queued/discarded the buffer. After calling
* BufferChannelBase::getOutputBufferArray(), the buffer and index match the
* returned array.
*/
virtual void onOutputBufferAvailable(
size_t index, const sp<MediaCodecBuffer> &buffer) = 0;
};
enum {
kMaxCodecBufferSize = 8192 * 4096 * 4, // 8K RGBA
};
inline void setCallback(std::unique_ptr<CodecCallback> &&callback) {
mCallback = std::move(callback);
}
virtual std::shared_ptr<BufferChannelBase> getBufferChannel() = 0;
virtual void initiateAllocateComponent(const sp<AMessage> &msg) = 0;
virtual void initiateConfigureComponent(const sp<AMessage> &msg) = 0;
virtual void initiateCreateInputSurface() = 0;
virtual void initiateSetInputSurface(
const sp<PersistentSurface> &surface) = 0;
virtual void initiateStart() = 0;
virtual void initiateShutdown(bool keepComponentAllocated = false) = 0;
// require an explicit message handler
virtual void onMessageReceived(const sp<AMessage> &msg) = 0;
virtual status_t setSurface(const sp<Surface>& /*surface*/, uint32_t /*generation*/) {
return INVALID_OPERATION;
}
virtual void signalFlush() = 0;
virtual void signalResume() = 0;
virtual void signalRequestIDRFrame() = 0;
virtual void signalSetParameters(const sp<AMessage> &msg) = 0;
virtual void signalEndOfInputStream() = 0;
/**
* Query supported parameters from this instance, and fill |names| with the
* names of the parameters.
*
* \param names string vector to fill with supported parameters.
* \return OK if successful;
* BAD_VALUE if |names| is null;
* INVALID_OPERATION if already released;
* ERROR_UNSUPPORTED if not supported.
*/
virtual status_t querySupportedParameters(std::vector<std::string> *names);
/**
* Fill |desc| with description of the parameter with |name|.
*
* \param name name of the parameter to describe
* \param desc pointer to CodecParameterDescriptor to be filled
* \return OK if successful;
* BAD_VALUE if |desc| is null;
* NAME_NOT_FOUND if |name| is not recognized by the component;
* INVALID_OPERATION if already released;
* ERROR_UNSUPPORTED if not supported.
*/
virtual status_t describeParameter(
const std::string &name,
CodecParameterDescriptor *desc);
/**
* Subscribe to parameters in |names| and get output format change event
* when they change.
* Unrecognized / already subscribed parameters are ignored.
*
* \param names names of parameters to subscribe
* \return OK if successful;
* INVALID_OPERATION if already released;
* ERROR_UNSUPPORTED if not supported.
*/
virtual status_t subscribeToParameters(const std::vector<std::string> &names);
/**
* Unsubscribe from parameters in |names| and no longer get
* output format change event when they change.
* Unrecognized / already unsubscribed parameters are ignored.
*
* \param names names of parameters to unsubscribe
* \return OK if successful;
* INVALID_OPERATION if already released;
* ERROR_UNSUPPORTED if not supported.
*/
virtual status_t unsubscribeFromParameters(const std::vector<std::string> &names);
typedef CodecBase *(*CreateCodecFunc)(void);
typedef PersistentSurface *(*CreateInputSurfaceFunc)(void);
protected:
CodecBase() = default;
virtual ~CodecBase() = default;
std::unique_ptr<CodecCallback> mCallback;
private:
DISALLOW_EVIL_CONSTRUCTORS(CodecBase);
};
/**
* A channel between MediaCodec and CodecBase object which manages buffer
* passing. Only MediaCodec is expected to call these methods, and
* underlying CodecBase implementation should define its own interface
* separately for itself.
*
* Concurrency assumptions:
*
* 1) Clients may access the object at multiple threads concurrently.
* 2) All methods do not call underlying CodecBase object while holding a lock.
* 3) Code inside critical section executes within 1ms.
*/
class BufferChannelBase {
public:
BufferChannelBase() = default;
virtual ~BufferChannelBase() = default;
inline void setCallback(std::unique_ptr<CodecBase::BufferCallback> &&callback) {
mCallback = std::move(callback);
}
virtual void setCrypto(const sp<ICrypto> &) {}
virtual void setDescrambler(const sp<IDescrambler> &) {}
/**
* Queue an input buffer into the buffer channel.
*
* @return OK if successful;
* -ENOENT if the buffer is not known (TODO: this should be
* handled gracefully in the future, here and below).
*/
virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) = 0;
/**
* Queue a secure input buffer into the buffer channel.
*
* @return OK if successful;
* -ENOENT if the buffer is not known;
* -ENOSYS if mCrypto is not set so that decryption is not
* possible;
* other errors if decryption failed.
*/
virtual status_t queueSecureInputBuffer(
const sp<MediaCodecBuffer> &buffer,
bool secure,
const uint8_t *key,
const uint8_t *iv,
CryptoPlugin::Mode mode,
CryptoPlugin::Pattern pattern,
const CryptoPlugin::SubSample *subSamples,
size_t numSubSamples,
AString *errorDetailMsg) = 0;
/**
* Queue a secure input buffer with multiple access units into the buffer channel.
*
* @param buffer The buffer to queue. The access unit delimiters and crypto
* subsample information is included in the buffer metadata.
* @param secure Whether the buffer is secure.
* @param errorDetailMsg The error message to be set in case of error.
* @return OK if successful;
* -ENOENT of the buffer is not known
* -ENOSYS if mCrypto is not set so that decryption is not
* possible;
* other errors if decryption failed.
*/
virtual status_t queueSecureInputBuffers(
const sp<MediaCodecBuffer> &buffer,
bool secure,
AString *errorDetailMsg) {
(void)buffer;
(void)secure;
(void)errorDetailMsg;
return -ENOSYS;
}
/**
* Attach a Codec 2.0 buffer to MediaCodecBuffer.
*
* @return OK if successful;
* -ENOENT if index is not recognized
* -ENOSYS if attaching buffer is not possible or not supported
*/
virtual status_t attachBuffer(
const std::shared_ptr<C2Buffer> &c2Buffer,
const sp<MediaCodecBuffer> &buffer) {
(void)c2Buffer;
(void)buffer;
return -ENOSYS;
}
/**
* Attach an encrypted HidlMemory buffer to an index
*
* @return OK if successful;
* -ENOENT if index is not recognized
* -ENOSYS if attaching buffer is not possible or not supported
*/
virtual status_t attachEncryptedBuffer(
const sp<hardware::HidlMemory> &memory,
bool secure,
const uint8_t *key,
const uint8_t *iv,
CryptoPlugin::Mode mode,
CryptoPlugin::Pattern pattern,
size_t offset,
const CryptoPlugin::SubSample *subSamples,
size_t numSubSamples,
const sp<MediaCodecBuffer> &buffer,
AString* errorDetailMsg) {
(void)memory;
(void)secure;
(void)key;
(void)iv;
(void)mode;
(void)pattern;
(void)offset;
(void)subSamples;
(void)numSubSamples;
(void)buffer;
(void)errorDetailMsg;
return -ENOSYS;
}
/**
* Attach an encrypted HidlMemory buffer containing multiple access units to an index
*
* @param memory The memory to attach.
* @param offset index???
* @param buffer The MediaCodecBuffer to attach the memory to. The access
* unit delimiters and crypto subsample information is included
* in the buffer metadata.
* @param secure Whether the buffer is secure.
* @param errorDetailMsg The error message to be set if an error occurs.
* @return OK if successful;
* -ENOENT if index is not recognized
* -ENOSYS if attaching buffer is not possible or not supported
*/
virtual status_t attachEncryptedBuffers(
const sp<hardware::HidlMemory> &memory,
size_t offset,
const sp<MediaCodecBuffer> &buffer,
bool secure,
AString* errorDetailMsg) {
(void)memory;
(void)offset;
(void)buffer;
(void)secure;
(void)errorDetailMsg;
return -ENOSYS;
}
/**
* Request buffer rendering at specified time.
*
* @param timestampNs nanosecond timestamp for rendering time.
* @return OK if successful;
* -ENOENT if the buffer is not known.
*/
virtual status_t renderOutputBuffer(
const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) = 0;
/**
* Poll for updates about rendered buffers.
*
* Triggers callbacks to CodecCallback::onOutputFramesRendered.
*/
virtual void pollForRenderedBuffers() = 0;
/**
* Notify a buffer is released from output surface.
*
* @param generation MediaCodec's surface specifier
*/
virtual void onBufferReleasedFromOutputSurface(uint32_t /*generation*/) {
// default: no-op
};
/**
* Discard a buffer to the underlying CodecBase object.
*
* TODO: remove once this operation can be handled by just clearing the
* reference.
*
* @return OK if successful;
* -ENOENT if the buffer is not known.
*/
virtual status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) = 0;
/**
* Clear and fill array with input buffers.
*/
virtual void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) = 0;
/**
* Clear and fill array with output buffers.
*/
virtual void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) = 0;
/**
* Convert binder IMemory to drm SharedBuffer
*
* \param memory IMemory object to store encrypted content.
* \param heapSeqNum Heap sequence number from ICrypto; -1 if N/A
* \param buf SharedBuffer structure to fill.
*/
static void IMemoryToSharedBuffer(
const sp<IMemory> &memory,
int32_t heapSeqNum,
hardware::drm::V1_0::SharedBuffer *buf);
protected:
std::unique_ptr<CodecBase::BufferCallback> mCallback;
};
} // namespace android
#endif // CODEC_BASE_H_