mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 804359 - Add support for detection of camcorder profiles at runtime. r=mikeh
This commit is contained in:
parent
7774dbed8d
commit
30838a3e4e
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -211,8 +211,7 @@ public:
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RecorderProfile)
|
||||
|
||||
RecorderProfile(const nsAString& aName)
|
||||
: mName(aName)
|
||||
RecorderProfile()
|
||||
{ }
|
||||
|
||||
const nsString& GetName() const { return mName; }
|
||||
|
Loading…
Reference in New Issue
Block a user