Bug 804359 - Add support for detection of camcorder profiles at runtime. r=mikeh

This commit is contained in:
Andrew Osmond 2014-12-02 15:14:17 -08:00
parent d3c0e156d7
commit 917eca3cd9
4 changed files with 146 additions and 67 deletions

View File

@ -24,19 +24,33 @@
using namespace mozilla;
using namespace android;
#define DEF_GONK_RECORDER_PROFILE(e, n) e##_INDEX,
enum {
#include "GonkRecorderProfiles.def"
PROFILE_COUNT
namespace mozilla {
struct ProfileConfig {
const char* name;
int quality;
};
#define DEF_GONK_RECORDER_PROFILE(e, n) { n, e },
static struct {
const char* name;
int quality;
} ProfileList[] = {
static const ProfileConfig ProfileList[] = {
#include "GonkRecorderProfiles.def"
{ nullptr, 0 }
};
static const size_t ProfileListSize = MOZ_ARRAY_LENGTH(ProfileList);
struct ProfileConfigDetect {
const char* name;
uint32_t width;
uint32_t height;
};
#define DEF_GONK_RECORDER_PROFILE_DETECT(n, w, h) { n, w, h },
static const ProfileConfigDetect ProfileListDetect[] = {
#include "GonkRecorderProfiles.def"
};
static const size_t ProfileListDetectSize = MOZ_ARRAY_LENGTH(ProfileListDetect);
};
/* static */ nsClassHashtable<nsUint32HashKey, ProfileHashtable> GonkRecorderProfile::sProfiles;
@ -53,19 +67,19 @@ GetMediaProfiles()
}
static bool
IsProfileSupported(uint32_t aCameraId, uint32_t aProfileIndex)
IsProfileSupported(uint32_t aCameraId, int aQuality)
{
MediaProfiles* profiles = GetMediaProfiles();
camcorder_quality q = static_cast<camcorder_quality>(ProfileList[aProfileIndex].quality);
return profiles->hasCamcorderProfile(static_cast<int>(aCameraId), q);
return profiles->hasCamcorderProfile(static_cast<int>(aCameraId),
static_cast<camcorder_quality>(aQuality));
}
static int
GetProfileParameter(uint32_t aCameraId, uint32_t aProfileIndex, const char* aParameter)
GetProfileParameter(uint32_t aCameraId, int aQuality, const char* aParameter)
{
MediaProfiles* profiles = GetMediaProfiles();
camcorder_quality q = static_cast<camcorder_quality>(ProfileList[aProfileIndex].quality);
return profiles->getCamcorderProfileParamByName(aParameter, static_cast<int>(aCameraId), q);
return profiles->getCamcorderProfileParamByName(aParameter, static_cast<int>(aCameraId),
static_cast<camcorder_quality>(aQuality));
}
/* static */ bool
@ -94,12 +108,12 @@ GonkRecorderVideo::Translate(video_encoder aCodec, nsAString& aCodecName)
int
GonkRecorderVideo::GetProfileParameter(const char* aParameter)
{
return ::GetProfileParameter(mCameraId, mProfileIndex, aParameter);
return ::GetProfileParameter(mCameraId, mQuality, aParameter);
}
GonkRecorderVideo::GonkRecorderVideo(uint32_t aCameraId, uint32_t aProfileIndex)
GonkRecorderVideo::GonkRecorderVideo(uint32_t aCameraId, int aQuality)
: mCameraId(aCameraId)
, mProfileIndex(aProfileIndex)
, mQuality(aQuality)
, mIsValid(false)
{
mPlatformEncoder = static_cast<video_encoder>(GetProfileParameter("vid.codec"));
@ -159,12 +173,12 @@ GonkRecorderAudio::Translate(audio_encoder aCodec, nsAString& aCodecName)
int
GonkRecorderAudio::GetProfileParameter(const char* aParameter)
{
return ::GetProfileParameter(mCameraId, mProfileIndex, aParameter);
return ::GetProfileParameter(mCameraId, mQuality, aParameter);
}
GonkRecorderAudio::GonkRecorderAudio(uint32_t aCameraId, uint32_t aProfileIndex)
GonkRecorderAudio::GonkRecorderAudio(uint32_t aCameraId, int aQuality)
: mCameraId(aCameraId)
, mProfileIndex(aProfileIndex)
, mQuality(aQuality)
, mIsValid(false)
{
mPlatformEncoder = static_cast<audio_encoder>(GetProfileParameter("aud.codec"));
@ -233,16 +247,15 @@ GonkRecorderProfile::GetMimeType(output_format aContainer, nsAString& aMimeType)
int
GonkRecorderProfile::GetProfileParameter(const char* aParameter)
{
return ::GetProfileParameter(mCameraId, mProfileIndex, aParameter);
return ::GetProfileParameter(mCameraId, mQuality, aParameter);
}
GonkRecorderProfile::GonkRecorderProfile(uint32_t aCameraId,
uint32_t aProfileIndex,
const nsAString& aName)
int aQuality)
: GonkRecorderProfileBase<GonkRecorderAudio, GonkRecorderVideo>(aCameraId,
aProfileIndex, aName)
aQuality)
, mCameraId(aCameraId)
, mProfileIndex(aProfileIndex)
, mQuality(aQuality)
, mIsValid(false)
{
mOutputFormat = static_cast<output_format>(GetProfileParameter("file.format"));
@ -264,28 +277,86 @@ GonkRecorderProfile::Enumerate(const nsAString& aProfileName,
return PL_DHASH_NEXT;
}
/* static */
already_AddRefed<GonkRecorderProfile>
GonkRecorderProfile::CreateProfile(uint32_t aCameraId, int aQuality)
{
if (!IsProfileSupported(aCameraId, aQuality)) {
DOM_CAMERA_LOGI("Profile %d not supported by platform\n", aQuality);
return nullptr;
}
nsRefPtr<GonkRecorderProfile> profile = new GonkRecorderProfile(aCameraId, aQuality);
if (!profile->IsValid()) {
DOM_CAMERA_LOGE("Profile %d is not valid\n", aQuality);
return nullptr;
}
return profile.forget();
}
/* static */
ProfileHashtable*
GonkRecorderProfile::GetProfileHashtable(uint32_t aCameraId)
{
ProfileHashtable* profiles = sProfiles.Get(aCameraId);
if (!profiles) {
profiles = new ProfileHashtable;
profiles = new ProfileHashtable();
sProfiles.Put(aCameraId, profiles);
for (uint32_t i = 0; ProfileList[i].name; ++i) {
if (IsProfileSupported(aCameraId, i)) {
DOM_CAMERA_LOGI("Profile %d '%s' supported by platform\n", i, ProfileList[i].name);
nsAutoString name;
name.AssignASCII(ProfileList[i].name);
nsRefPtr<GonkRecorderProfile> profile = new GonkRecorderProfile(aCameraId, i, name);
if (!profile->IsValid()) {
DOM_CAMERA_LOGE("Profile %d '%s' is not valid\n", i, ProfileList[i].name);
continue;
/* First handle the profiles with a known enum. We can process those
efficently because MediaProfiles indexes their profiles that way. */
int highestKnownQuality = CAMCORDER_QUALITY_LIST_START - 1;
for (size_t i = 0; i < ProfileListSize; ++i) {
const ProfileConfig& p = ProfileList[i];
if (p.quality > highestKnownQuality) {
highestKnownQuality = p.quality;
}
nsRefPtr<GonkRecorderProfile> profile = CreateProfile(aCameraId, p.quality);
if (!profile) {
continue;
}
DOM_CAMERA_LOGI("Profile %d '%s' supported by platform\n", p.quality, p.name);
profile->mName.AssignASCII(p.name);
profiles->Put(profile->GetName(), profile);
}
/* However not all of the potentially supported profiles have a known
enum on all of our supported platforms because some entries may
be missing from MediaProfiles.h. As such, we can't rely upon
having the CAMCORDER_QUALITY_* enums for those profiles. We need
to map the profiles to a name by matching the width and height of
the video resolution to our configured values.
In theory there may be collisions given that there can be multiple
resolutions sharing the same name (e.g. 800x480 and 768x480 are both
wvga). In practice this should not happen because there should be
only one WVGA profile given there is only one enum for it. In the
situation there is a collision, it will merely select the last
detected profile. */
for (int q = highestKnownQuality + 1; q <= CAMCORDER_QUALITY_LIST_END; ++q) {
nsRefPtr<GonkRecorderProfile> profile = CreateProfile(aCameraId, q);
if (!profile) {
continue;
}
const ICameraControl::Size& s = profile->GetVideo().GetSize();
size_t match;
for (match = 0; match < ProfileListDetectSize; ++match) {
const ProfileConfigDetect& p = ProfileListDetect[match];
if (s.width == p.width && s.height == p.height) {
DOM_CAMERA_LOGI("Profile %d '%s' supported by platform\n", q, p.name);
profile->mName.AssignASCII(p.name);
profiles->Put(profile->GetName(), profile);
break;
}
profiles->Put(name, profile);
} else {
DOM_CAMERA_LOGI("Profile %d '%s' not supported by platform\n", i, ProfileList[i].name);
}
if (match == ProfileListDetectSize) {
DOM_CAMERA_LOGW("Profile %d size %u x %u is not recognized\n",
q, s.width, s.height);
}
}
}

View File

@ -18,6 +18,14 @@
* DO NOT PUT RE-INCLUSION GUARD MACROS AROUND THIS HEADER!!!
*/
#ifndef DEF_GONK_RECORDER_PROFILE
#define DEF_GONK_RECORDER_PROFILE(e, n)
#endif
#ifndef DEF_GONK_RECORDER_PROFILE_DETECT
#define DEF_GONK_RECORDER_PROFILE_DETECT(n, w, h)
#endif
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_LOW, "low")
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_HIGH, "high")
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_QCIF, "qcif")
@ -25,21 +33,21 @@ DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_CIF, "cif")
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_480P, "480p")
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_720P, "720p")
DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_1080P, "1080p")
/**
* This profile is disabled because the CAMCORDER_QUALITY_QVGA value
* conflicts across AOSP and vendor-specific versions of MediaProfiles.h.
*
* See bug 804359.
* The following profiles do not appear in all versions of the
* MediaProfiles.h and must be detected at runtime. Additionally some
* profiles may have more than one resolution, depending on the camera.
*/
// DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_QVGA, "qvga")
/**
* The following profiles do not appear in the AOSP version of
* MediaProfiles.h and are disabled.
*
* See bug 804359.
*/
// DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_FWVGA, "fwvga")
// DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_WVGA, "wvga")
// DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_VGA, "vga")
// DEF_GONK_RECORDER_PROFILE(CAMCORDER_QUALITY_WQVGA, "wqvga")
DEF_GONK_RECORDER_PROFILE_DETECT("fwvga", 864, 480)
DEF_GONK_RECORDER_PROFILE_DETECT("fwvga", 854, 480)
DEF_GONK_RECORDER_PROFILE_DETECT("wvga", 800, 480)
DEF_GONK_RECORDER_PROFILE_DETECT("wvga", 768, 480)
DEF_GONK_RECORDER_PROFILE_DETECT("vga", 640, 480)
DEF_GONK_RECORDER_PROFILE_DETECT("hvga", 480, 320)
DEF_GONK_RECORDER_PROFILE_DETECT("wqvga", 400, 240)
DEF_GONK_RECORDER_PROFILE_DETECT("qvga", 320, 240)
#undef DEF_GONK_RECORDER_PROFILE
#undef DEF_GONK_RECORDER_PROFILE_DETECT

View File

@ -37,10 +37,10 @@ template<class A, class V>
class GonkRecorderProfileBase : public ICameraControl::RecorderProfile
{
public:
GonkRecorderProfileBase(uint32_t aCameraId, uint32_t aProfileIndex, const nsAString& aName)
: RecorderProfile(aName)
, mAudio(aCameraId, aProfileIndex)
, mVideo(aCameraId, aProfileIndex)
GonkRecorderProfileBase(uint32_t aCameraId, int aQuality)
: RecorderProfile()
, mAudio(aCameraId, aQuality)
, mVideo(aCameraId, aQuality)
{ }
virtual const Audio& GetAudio() const MOZ_OVERRIDE { return mAudio; }
@ -58,7 +58,7 @@ protected:
class GonkRecorderVideo : public ICameraControl::RecorderProfile::Video
{
public:
GonkRecorderVideo(uint32_t aCameraId, uint32_t aProfileIndex);
GonkRecorderVideo(uint32_t aCameraId, int aQuality);
virtual ~GonkRecorderVideo() { }
android::video_encoder GetPlatformEncoder() const { return mPlatformEncoder; }
@ -69,7 +69,7 @@ protected:
static bool Translate(android::video_encoder aCodec, nsAString& aCodecName);
uint32_t mCameraId;
uint32_t mProfileIndex;
int mQuality;
bool mIsValid;
android::video_encoder mPlatformEncoder;
};
@ -80,7 +80,7 @@ protected:
class GonkRecorderAudio : public ICameraControl::RecorderProfile::Audio
{
public:
GonkRecorderAudio(uint32_t aCameraId, uint32_t aProfileIndex);
GonkRecorderAudio(uint32_t aCameraId, int aQuality);
virtual ~GonkRecorderAudio() { }
android::audio_encoder GetPlatformEncoder() const { return mPlatformEncoder; }
@ -91,7 +91,7 @@ protected:
static bool Translate(android::audio_encoder aCodec, nsAString& aCodecName);
uint32_t mCameraId;
uint32_t mProfileIndex;
int mQuality;
bool mIsValid;
android::audio_encoder mPlatformEncoder;
};
@ -121,8 +121,7 @@ public:
protected:
GonkRecorderProfile(uint32_t aCameraId,
uint32_t aProfileIndex,
const nsAString& aName);
int aQuality);
int GetProfileParameter(const char* aParameter);
@ -131,13 +130,15 @@ protected:
bool IsValid() const { return mIsValid; };
nsresult ConfigureRecorder(android::GonkRecorder& aRecorder);
static already_AddRefed<GonkRecorderProfile> CreateProfile(uint32_t aCameraId,
int aQuality);
static ProfileHashtable* GetProfileHashtable(uint32_t aCameraId);
static PLDHashOperator Enumerate(const nsAString& aProfileName,
GonkRecorderProfile* aProfile,
void* aUserArg);
uint32_t mCameraId;
uint32_t mProfileIndex;
int mQuality;
bool mIsValid;
android::output_format mOutputFormat;

View File

@ -211,8 +211,7 @@ public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RecorderProfile)
RecorderProfile(const nsAString& aName)
: mName(aName)
RecorderProfile()
{ }
const nsString& GetName() const { return mName; }