You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
5.6 KiB

// 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 <VideoToolbox/VideoToolbox.h>
#include <cstdint>
#include <string>
#include <vector>
#include <stdio.h>
#include <string.h>
#ifndef kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder
#define kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder CFSTR("RequireHardwareAcceleratedVideoDecoder")
#endif
#include <stddef.h>
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<uint8_t> getSPS() const { return mSPS; }
std::vector<uint8_t> 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<uint8_t> mSPS; // sps NALU
std::vector<uint8_t> mPPS; // pps NALU
bool mIsInFlush = false;
private:
bool mIsLoadingFromSnapshot = false;
std::vector<uint8_t> mSavedDecodedFrame;
void copyFrame();
void oneShotDecode(std::vector<uint8_t> & data, uint64_t pts);
mutable SnapshotState mSnapshotState;
}; // MediaH264DecoderVideoToolBox
} // namespace emulation
} // namespace android