// Copyright (C) 2019 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. #pragma once #include "host-common/GoldfishMediaDefs.h" #include "host-common/H264NaluParser.h" #include "host-common/H264PingInfoParser.h" #include "host-common/MediaCodec.h" #include "host-common/MediaH264DecoderPlugin.h" #include "host-common/MediaHostRenderer.h" #include #include #include #include #include #include #ifndef kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder #define kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder CFSTR("RequireHardwareAcceleratedVideoDecoder") #endif #include namespace android { namespace emulation { class MediaH264DecoderVideoToolBox : public MediaH264DecoderPlugin { public: virtual void initH264Context(void* ptr) override; virtual void reset(void* ptr) override; virtual MediaH264DecoderPlugin* clone() override; virtual void destroyH264Context() override; virtual void decodeFrame(void* ptr) override; virtual void flush(void* ptr) override; virtual void getImage(void* ptr) override; virtual void save(base::Stream* stream) const override; virtual bool load(base::Stream* stream) override; virtual int type() const override { return PLUGIN_TYPE_VIDEO_TOOL_BOX; } explicit MediaH264DecoderVideoToolBox(uint64_t id, H264PingInfoParser parser); virtual ~MediaH264DecoderVideoToolBox(); public: enum class DecoderState { BAD_STATE = 0, GOOD_STATE = 1, }; DecoderState getState() const {return mState;} std::vector getSPS() const { return mSPS; } std::vector getPPS() const { return mPPS; } private: void initH264ContextInternal(unsigned int width, unsigned int height, unsigned int outWidth, unsigned int outHeight, PixelFormat pixFmt); uint64_t mId = 0; H264PingInfoParser mParser; MediaHostRenderer mRenderer; DecoderState mState = DecoderState::GOOD_STATE; void decodeFrameInternal(size_t* pRetSzBytes, int32_t* pRetErr, const uint8_t* frame, size_t szBytes, uint64_t pts, size_t consumedSzBytes); // Passes the Sequence Parameter Set (SPS) and Picture Parameter Set (PPS) to the // videotoolbox decoder CFDataRef createVTDecoderConfig(); // Callback passed to the VTDecompressionSession static void videoToolboxDecompressCallback(void* opaque, void* sourceFrameRefCon, OSStatus status, VTDecodeInfoFlags flags, CVImageBufferRef image_buffer, CMTime pts, CMTime duration); static CFDictionaryRef createOutputBufferAttributes(int width, int height, OSType pix_fmt); static CMSampleBufferRef createSampleBuffer(CMFormatDescriptionRef fmtDesc, void* buffer, size_t sz); static OSType toNativePixelFormat(PixelFormat fmt); // We should move these shared memory calls elsewhere, as vpx decoder is also using the same/similar // functions static void* getReturnAddress(void* ptr); static uint8_t* getDst(void* ptr); void handleIDRFrame(const uint8_t* ptr, size_t szBytes, uint64_t pts); void handleNonIDRFrame(const uint8_t* ptr, size_t szBytes, uint64_t pts); void handleSEIFrame(const uint8_t* ptr, size_t szBytes); void createCMFormatDescription(); void recreateDecompressionSession(); // The VideoToolbox decoder session VTDecompressionSessionRef mDecoderSession = nullptr; // The decoded video buffer uint64_t mOutputPts = 0; CVImageBufferRef mDecodedFrame = nullptr; CMFormatDescriptionRef mCmFmtDesc = nullptr; bool mImageReady = false; static constexpr int kBPP = 2; // YUV420 is 2 bytes per pixel unsigned int mOutputHeight = 0; unsigned int mOutputWidth = 0; unsigned int mWidth = 0; unsigned int mHeight = 0; PixelFormat mOutPixFmt; // The calculated size of the outHeader buffer size allocated in the guest. // It should be sizeY + (sizeUV * 2), where: // sizeY = outWidth * outHeight, // sizeUV = sizeY / 4 // It is equivalent to outWidth * outHeight * 3 / 2 unsigned int mOutBufferSize = 0; std::vector mSPS; // sps NALU std::vector mPPS; // pps NALU bool mIsInFlush = false; private: bool mIsLoadingFromSnapshot = false; std::vector mSavedDecodedFrame; void copyFrame(); void oneShotDecode(std::vector & data, uint64_t pts); mutable SnapshotState mSnapshotState; }; // MediaH264DecoderVideoToolBox } // namespace emulation } // namespace android