blob: 8a1751e402ddbb67e43996cfc8dcefdc272ca8ee [file] [log] [blame]
/*
* Copyright (C) 2017 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 _NATIVE_MEDIA_UTILS_H_
#define _NATIVE_MEDIA_UTILS_H_
#include <pthread.h>
#include <sys/cdefs.h>
#include <stddef.h>
#include <assert.h>
#include <vector>
#include <android/native_window_jni.h>
#include "media/NdkMediaFormat.h"
#include "media/NdkMediaExtractor.h"
#include "media/NdkMediaCodec.h"
#include "media/NdkMediaMuxer.h"
namespace Utils {
// constants not defined in NDK api
extern const char * TBD_AMEDIACODEC_PARAMETER_KEY_REQUEST_SYNC_FRAME;
extern const char * TBD_AMEDIACODEC_PARAMETER_KEY_VIDEO_BITRATE;
static const uint32_t TBD_AMEDIACODEC_BUFFER_FLAG_KEY_FRAME = 0x1;
extern const char * TBD_AMEDIAFORMAT_KEY_BIT_RATE_MODE;
static const int32_t kBitrateModeConstant = 2;
static const int32_t kColorFormatSurface = 0x7f000789;
// tolerances
// Keep in sync with the variation at src/android/media/cts/VideoCodecTest.java
static const float kBitrateDeviationPercentMax = 20.0;
static const int32_t kSyncFrameDeviationFramesMax = 5;
enum Status : int32_t {
FAIL = -1,
OK = 0,
};
class Thread {
public:
Thread()
: mHandle(0) {
}
virtual ~Thread() {
assert(mExited);
mHandle = 0;
}
Thread(const Thread& ) = delete;
Status startThread();
Status joinThread();
protected:
virtual void run() = 0;
private:
static void* thread_wrapper(void *);
pthread_t mHandle;
};
static inline void deleter_AMediExtractor(AMediaExtractor *_a) {
AMediaExtractor_delete(_a);
}
static inline void deleter_AMediaCodec(AMediaCodec *_a) {
AMediaCodec_delete(_a);
}
static inline void deleter_AMediaFormat(AMediaFormat *_a) {
AMediaFormat_delete(_a);
}
static inline void deleter_AMediaMuxer(AMediaMuxer *_a) {
AMediaMuxer_delete(_a);
}
static inline void deleter_ANativeWindow(ANativeWindow *_a) {
ANativeWindow_release(_a);
}
/*
* Dynamic paramater that will be applied via AMediaCodec_setParamater(..)
* during the encoding process, at the given frame number
*/
struct DynamicParam {
DynamicParam() = delete;
DynamicParam(const DynamicParam&) = delete;
~DynamicParam() = default;
static std::shared_ptr<DynamicParam> newBitRate(int atFrame, int32_t bitrate) {
DynamicParam *d = new DynamicParam(atFrame);
AMediaFormat_setInt32(d->param(), TBD_AMEDIACODEC_PARAMETER_KEY_VIDEO_BITRATE, bitrate);
return std::shared_ptr<DynamicParam>(d);
}
static std::shared_ptr<DynamicParam> newRequestSync(int atFrame) {
DynamicParam *d = new DynamicParam(atFrame);
AMediaFormat_setInt32(d->param(), TBD_AMEDIACODEC_PARAMETER_KEY_REQUEST_SYNC_FRAME, 0 /*ignore*/);
return std::shared_ptr<DynamicParam>(d);
}
inline int frameNum() const {
return mFrameNum;
}
inline AMediaFormat *param() const {
return mParam.get();
}
private:
DynamicParam(int _at)
: mFrameNum(_at) {
mParam = std::shared_ptr<AMediaFormat>(AMediaFormat_new(), deleter_AMediaFormat);
}
int mFrameNum;
std::shared_ptr<AMediaFormat> mParam;
};
using DParamRef = std::shared_ptr<DynamicParam>;
/*
* Configuration to the encoder (static + dynamic)
*/
struct RunConfig {
RunConfig(const RunConfig&) = delete;
RunConfig(int32_t numFramesToEncode, std::shared_ptr<AMediaFormat> staticParams)
: mNumFramesToEncode (numFramesToEncode),
mStaticParams(staticParams) {
}
void add(const DParamRef& p) {
mParams.push_back(p);
}
AMediaFormat* format() const {
return mStaticParams.get();
}
const std::vector<DParamRef>& dynamicParams() const {
return mParams;
}
int32_t frameCount() const {
return mNumFramesToEncode;
}
int32_t dynamicParamsOfKind(
const char *key, std::vector<DParamRef>& ) const;
private:
int32_t mNumFramesToEncode;
std::vector<DParamRef> mParams;
std::shared_ptr<AMediaFormat> mStaticParams;
};
/*
* Encoded output statistics
* provides helpers to compute windowed average of bitrate and search for I-frames
*/
struct Stats {
Stats() = default;
Stats(const Stats&) = delete;
void add(const AMediaCodecBufferInfo &info) {
mInfos.push_back(info);
}
void setOutputFormat(std::shared_ptr<AMediaFormat> fmt) {
mOutputFormat = fmt;
}
int32_t frameCount() const {
return (int32_t)mInfos.size();
}
const std::vector<AMediaCodecBufferInfo>& infos() const {
return mInfos;
}
int32_t getBitrateAverage(int32_t frameNumFrom, int32_t frameNumTo) const;
int32_t getBitratePeak(int32_t frameNumFrom, int32_t frameNumTo, int32_t windowSize) const;
int32_t getSyncFrameNext(int32_t frameNumWhence) const;
private:
std::vector<AMediaCodecBufferInfo> mInfos;
std::shared_ptr<AMediaFormat> mOutputFormat;
};
/*
* Helpers to validate output (Stats) based on expected settings (RunConfig)
* Check for validity of both static and dynamic settings
*/
struct Validator {
static Status checkOverallBitrate(const Stats&, const RunConfig&);
static Status checkFramerate(const Stats&, const RunConfig&);
static Status checkIntraPeriod(const Stats&, const RunConfig&);
static Status checkDynamicKeyFrames(const Stats&, const RunConfig&);
static Status checkDynamicBitrate(const Stats&, const RunConfig&);
};
}; //namespace Utils
#endif // _NATIVE_MEDIA_UTILS_H_