Initial check-in for xml-based encoder capabilities retrieval
- Changed the Java API as suggested
- Treat /etc/media_profiles.xml as the default xml configurtion file
diff --git a/include/media/MediaProfiles.h b/include/media/MediaProfiles.h
new file mode 100644
index 0000000..be928ec
--- /dev/null
+++ b/include/media/MediaProfiles.h
@@ -0,0 +1,303 @@
+/*
+ **
+ ** Copyright 2010, 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 ANDROID_MEDIAPROFILES_H
+#define ANDROID_MEDIAPROFILES_H
+
+#include <utils/threads.h>
+#include <media/mediarecorder.h>
+
+namespace android {
+
+enum camcorder_quality {
+    CAMCORDER_QUALITY_HIGH = 0,
+    CAMCORDER_QUALITY_LOW  = 1
+};
+
+enum video_decoder {
+    VIDEO_DECODER_WMV,
+};
+
+enum audio_decoder {
+    AUDIO_DECODER_WMA,
+};
+
+
+class MediaProfiles
+{
+public:
+
+    /**
+     * Returns the singleton instance for subsequence queries.
+     * or NULL if error.
+     */
+    static MediaProfiles* getInstance();
+
+    /**
+     * Returns the value for the given param name at the given quality level,
+     * or -1 if error.
+     *
+     * Supported param name are:
+     * file.format - output file format. see mediarecorder.h for details
+     * codec.vid - video encoder. see mediarecorder.h for details.
+     * codec.aud - audio encoder. see mediarecorder.h for details.
+     * vid.width - video frame width
+     * vid.height - video frame height
+     * vid.fps - video frame rate
+     * vid.bps - video bit rate
+     * aud.bps - audio bit rate
+     * aud.hz - audio sample rate
+     * aud.ch - number of audio channels
+     */
+    int getCamcorderProfileParamByName(const char *name, camcorder_quality quality) const;
+
+    /**
+     * Returns the output file formats supported.
+     */
+    Vector<output_format> getOutputFileFormats() const;
+
+    /**
+     * Returns the video encoders supported.
+     */
+    Vector<video_encoder> getVideoEncoders() const;
+
+    /**
+     * Returns the value for the given param name for the given video encoder
+     * returned from getVideoEncoderByIndex or -1 if error.
+     *
+     * Supported param name are:
+     * enc.vid.width.min - min video frame width
+     * enc.vid.width.max - max video frame width
+     * enc.vid.height.min - min video frame height
+     * enc.vid.height.max - max video frame height
+     * enc.vid.bps.min - min bit rate in bits per second
+     * enc.vid.bps.max - max bit rate in bits per second
+     * enc.vid.fps.min - min frame rate in frames per second
+     * enc.vid.fps.max - max frame rate in frames per second
+     */
+    int getVideoEncoderParamByName(const char *name, video_encoder codec) const;
+
+    /**
+     * Returns the audio encoders supported.
+     */
+    Vector<audio_encoder> getAudioEncoders() const;
+
+    /**
+     * Returns the value for the given param name for the given audio encoder
+     * returned from getAudioEncoderByIndex or -1 if error.
+     *
+     * Supported param name are:
+     * enc.aud.ch.min - min number of channels
+     * enc.aud.ch.max - max number of channels
+     * enc.aud.bps.min - min bit rate in bits per second
+     * enc.aud.bps.max - max bit rate in bits per second
+     * enc.aud.hz.min - min sample rate in samples per second
+     * enc.aud.hz.max - max sample rate in samples per second
+     */
+    int getAudioEncoderParamByName(const char *name, audio_encoder codec) const;
+
+    /**
+      * Returns the video decoders supported.
+      */
+    Vector<video_decoder> getVideoDecoders() const;
+
+     /**
+      * Returns the audio decoders supported.
+      */
+    Vector<audio_decoder> getAudioDecoders() const;
+
+private:
+    MediaProfiles& operator=(const MediaProfiles&);  // Don't call me
+    MediaProfiles(const MediaProfiles&);             // Don't call me
+    MediaProfiles() {}                               // Dummy default constructor
+    ~MediaProfiles();                                // Don't delete me
+
+    struct VideoCodec {
+        VideoCodec(video_encoder codec, int bitRate, int frameWidth, int frameHeight, int frameRate)
+            : mCodec(codec),
+              mBitRate(bitRate),
+              mFrameWidth(frameWidth),
+              mFrameHeight(frameHeight),
+              mFrameRate(frameRate) {}
+
+        ~VideoCodec() {}
+
+        video_encoder mCodec;
+        int mBitRate;
+        int mFrameWidth;
+        int mFrameHeight;
+        int mFrameRate;
+    };
+
+    struct AudioCodec {
+        AudioCodec(audio_encoder codec, int bitRate, int sampleRate, int channels)
+            : mCodec(codec),
+              mBitRate(bitRate),
+              mSampleRate(sampleRate),
+              mChannels(channels) {}
+
+        ~AudioCodec() {}
+
+        audio_encoder mCodec;
+        int mBitRate;
+        int mSampleRate;
+        int mChannels;
+    };
+
+    struct CamcorderProfile {
+        CamcorderProfile()
+            : mFileFormat(OUTPUT_FORMAT_THREE_GPP),
+              mQuality(CAMCORDER_QUALITY_HIGH),
+              mDuration(0),
+              mVideoCodec(0),
+              mAudioCodec(0) {}
+
+        ~CamcorderProfile() {
+            delete mVideoCodec;
+            delete mAudioCodec;
+        }
+
+        output_format mFileFormat;
+        camcorder_quality mQuality;
+        int mDuration;
+        VideoCodec *mVideoCodec;
+        AudioCodec *mAudioCodec;
+    };
+
+    struct VideoEncoderCap {
+        // Ugly constructor
+        VideoEncoderCap(video_encoder codec,
+                        int minBitRate, int maxBitRate,
+                        int minFrameWidth, int maxFrameWidth,
+                        int minFrameHeight, int maxFrameHeight,
+                        int minFrameRate, int maxFrameRate)
+            : mCodec(codec),
+              mMinBitRate(minBitRate), mMaxBitRate(maxBitRate),
+              mMinFrameWidth(minFrameWidth), mMaxFrameWidth(maxFrameWidth),
+              mMinFrameHeight(minFrameHeight), mMaxFrameHeight(maxFrameHeight),
+              mMinFrameRate(minFrameRate), mMaxFrameRate(maxFrameRate) {}
+
+         ~VideoEncoderCap() {}
+
+        video_encoder mCodec;
+        int mMinBitRate, mMaxBitRate;
+        int mMinFrameWidth, mMaxFrameWidth;
+        int mMinFrameHeight, mMaxFrameHeight;
+        int mMinFrameRate, mMaxFrameRate;
+    };
+
+    struct AudioEncoderCap {
+        // Ugly constructor
+        AudioEncoderCap(audio_encoder codec,
+                        int minBitRate, int maxBitRate,
+                        int minSampleRate, int maxSampleRate,
+                        int minChannels, int maxChannels)
+            : mCodec(codec),
+              mMinBitRate(minBitRate), mMaxBitRate(maxBitRate),
+              mMinSampleRate(minSampleRate), mMaxSampleRate(maxSampleRate),
+              mMinChannels(minChannels), mMaxChannels(maxChannels) {}
+
+        ~AudioEncoderCap() {}
+
+        audio_encoder mCodec;
+        int mMinBitRate, mMaxBitRate;
+        int mMinSampleRate, mMaxSampleRate;
+        int mMinChannels, mMaxChannels;
+    };
+
+    struct VideoDecoderCap {
+        VideoDecoderCap(video_decoder codec): mCodec(codec) {}
+        ~VideoDecoderCap() {}
+
+        video_decoder mCodec;
+    };
+
+    struct AudioDecoderCap {
+        AudioDecoderCap(audio_decoder codec): mCodec(codec) {}
+        ~AudioDecoderCap() {}
+
+        audio_decoder mCodec;
+    };
+
+    struct NameToTagMap {
+        const char* name;
+        int tag;
+    };
+
+    // Debug
+    static void logVideoCodec(const VideoCodec& codec);
+    static void logAudioCodec(const AudioCodec& codec);
+    static void logVideoEncoderCap(const VideoEncoderCap& cap);
+    static void logAudioEncoderCap(const AudioEncoderCap& cap);
+    static void logVideoDecoderCap(const VideoDecoderCap& cap);
+    static void logAudioDecoderCap(const AudioDecoderCap& cap);
+
+    // If the xml configuration file does exist, use the settings
+    // from the xml
+    static MediaProfiles* createInstanceFromXmlFile(const char *xml);
+    static output_format createEncoderOutputFileFormat(const char **atts);
+    static VideoCodec* createVideoCodec(const char **atts, MediaProfiles *profiles);
+    static AudioCodec* createAudioCodec(const char **atts, MediaProfiles *profiles);
+    static AudioDecoderCap* createAudioDecoderCap(const char **atts);
+    static VideoDecoderCap* createVideoDecoderCap(const char **atts);
+    static VideoEncoderCap* createVideoEncoderCap(const char **atts);
+    static AudioEncoderCap* createAudioEncoderCap(const char **atts);
+    static CamcorderProfile* createCamcorderProfile(const char **atts);
+
+    // Customized element tag handler for parsing the xml configuration file.
+    static void startElementHandler(void *userData, const char *name, const char **atts);
+
+    // If the xml configuration file does not exist, use hard-coded values
+    static MediaProfiles* createDefaultInstance();
+    static CamcorderProfile *createDefaultCamcorderLowProfile();
+    static CamcorderProfile *createDefaultCamcorderHighProfile();
+    static void createDefaultCamcorderProfiles(MediaProfiles *profiles);
+    static void createDefaultVideoEncoders(MediaProfiles *profiles);
+    static void createDefaultAudioEncoders(MediaProfiles *profiles);
+    static void createDefaultVideoDecoders(MediaProfiles *profiles);
+    static void createDefaultAudioDecoders(MediaProfiles *profiles);
+    static void createDefaultEncoderOutputFileFormats(MediaProfiles *profiles);
+    static VideoEncoderCap* createDefaultH263VideoEncoderCap();
+    static VideoEncoderCap* createDefaultM4vVideoEncoderCap();
+    static AudioEncoderCap* createDefaultAmrNBEncoderCap();
+
+    static int findTagForName(const NameToTagMap *map, size_t nMappings, const char *name);
+
+    // Mappings from name (for instance, codec name) to enum value
+    static const NameToTagMap sVideoEncoderNameMap[];
+    static const NameToTagMap sAudioEncoderNameMap[];
+    static const NameToTagMap sFileFormatMap[];
+    static const NameToTagMap sVideoDecoderNameMap[];
+    static const NameToTagMap sAudioDecoderNameMap[];
+    static const NameToTagMap sCamcorderQualityNameMap[];
+
+    static bool sIsInitialized;
+    static MediaProfiles *sInstance;
+    static Mutex sLock;
+
+    Vector<CamcorderProfile*> mCamcorderProfiles;
+    Vector<AudioEncoderCap*>  mAudioEncoders;
+    Vector<VideoEncoderCap*>  mVideoEncoders;
+    Vector<AudioDecoderCap*>  mAudioDecoders;
+    Vector<VideoDecoderCap*>  mVideoDecoders;
+    Vector<output_format>     mEncoderOutputFileFormats;
+};
+
+}; // namespace android
+
+#endif // ANDROID_MEDIAPROFILES_H
+
diff --git a/media/java/android/media/EncoderCapabilities.java b/media/java/android/media/EncoderCapabilities.java
new file mode 100644
index 0000000..71cb1b3
--- /dev/null
+++ b/media/java/android/media/EncoderCapabilities.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package android.media;
+
+import java.util.List;
+import java.util.ArrayList;
+import android.util.Log;
+
+/**
+ * The EncoderCapabilities class is used to retrieve the
+ * capabilities for different video and audio
+ * encoders supported on a specific Android platform.
+ * {@hide}
+ */
+public class EncoderCapabilities
+{
+    private static final String TAG = "EncoderCapabilities";
+
+    /**
+     * The VideoEncoderCap class represents a video encoder's
+     * supported parameter range in:
+     *
+     * <ul>
+     * <li>Resolution: the frame size (width/height) in pixels;
+     * <li>Bit rate: the compressed output bit rate in bits per second;
+     * <li>Frame rate: the output number of frames per second.
+     * </ul>
+     *
+     */
+    static public class VideoEncoderCap {
+        // These are not modifiable externally, thus are public accessible
+        public final int mCodec;                                 // @see android.media.MediaRecorder.VideoEncoder
+        public final int mMinBitRate, mMaxBitRate;               // min and max bit rate (bps)
+        public final int mMinFrameRate, mMaxFrameRate;           // min and max frame rate (fps)
+        public final int mMinFrameWidth, mMaxFrameWidth;         // min and max frame width (pixel)
+        public final int mMinFrameHeight, mMaxFrameHeight;       // minn and max frame height (pixel)
+
+        // Private constructor called by JNI
+        private VideoEncoderCap(int codec,
+                                int minBitRate, int maxBitRate,
+                                int minFrameRate, int maxFrameRate,
+                                int minFrameWidth, int maxFrameWidth,
+                                int minFrameHeight, int maxFrameHeight) {
+            mCodec = codec;
+            mMinBitRate = minBitRate;
+            mMaxBitRate = maxBitRate;
+            mMinFrameRate = minFrameRate;
+            mMaxFrameRate = maxFrameRate;
+            mMinFrameWidth = minFrameWidth;
+            mMaxFrameWidth = maxFrameWidth;
+            mMinFrameHeight = minFrameHeight;
+            mMaxFrameHeight = maxFrameHeight;
+        }
+    };
+
+    /**
+     * The AudioEncoderCap class represents an audio encoder's
+     * parameter range in:
+     *
+     * <ul>
+     * <li>Bit rate: the compressed output bit rate in bits per second;
+     * <li>Sample rate: the sampling rate used for recording the audio in samples per second;
+     * <li>Number of channels: the number of channels the audio is recorded.
+     * </ul>
+     *
+     */
+    static public class AudioEncoderCap {
+        // These are not modifiable externally, thus are public accessible
+        public final int mCodec;                         // @see android.media.MediaRecorder.AudioEncoder
+        public final int mMinChannels, mMaxChannels;     // min and max number of channels
+        public final int mMinSampleRate, mMaxSampleRate; // min and max sample rate (hz)
+        public final int mMinBitRate, mMaxBitRate;       // min and max bit rate (bps)
+
+        // Private constructor called by JNI
+        private AudioEncoderCap(int codec,
+                                int minBitRate, int maxBitRate,
+                                int minSampleRate, int maxSampleRate,
+                                int minChannels, int maxChannels) {
+           mCodec = codec;
+           mMinBitRate = minBitRate;
+           mMaxBitRate = maxBitRate;
+           mMinSampleRate = minSampleRate;
+           mMaxSampleRate = maxSampleRate;
+           mMinChannels = minChannels;
+           mMaxChannels = maxChannels;
+       }
+    };
+
+    static {
+        System.loadLibrary("media_jni");
+        native_init();
+    }
+
+    /**
+     * Returns the array of supported output file formats.
+     * @see android.media.MediaRecorder.OutputFormat
+     */
+    public static int[] getOutputFileFormats() {
+        int nFormats = native_get_num_file_formats();
+        if (nFormats == 0) return null;
+
+        int[] formats = new int[nFormats];
+        for (int i = 0; i < nFormats; ++i) {
+            formats[i] = native_get_file_format(i);
+        }
+        return formats;
+    }
+
+    /**
+     * Returns the capabilities of the supported video encoders.
+     * @see android.media.EncoderCapabilities.VideoEncoderCap
+     */
+    public static List<VideoEncoderCap> getVideoEncoders() {
+        int nEncoders = native_get_num_video_encoders();
+        if (nEncoders == 0) return null;
+
+        List<VideoEncoderCap> encoderList = new ArrayList<VideoEncoderCap>();
+        for (int i = 0; i < nEncoders; ++i) {
+            encoderList.add(native_get_video_encoder_cap(i));
+        }
+        return encoderList;
+    }
+
+    /**
+     * Returns the capabilities of the supported audio encoders.
+     * @see android.media.EncoderCapabilities.AudioEncoderCap
+     */
+    public static List<AudioEncoderCap> getAudioEncoders() {
+        int nEncoders = native_get_num_audio_encoders();
+        if (nEncoders == 0) return null;
+
+        List<AudioEncoderCap> encoderList = new ArrayList<AudioEncoderCap>();
+        for (int i = 0; i < nEncoders; ++i) {
+            encoderList.add(native_get_audio_encoder_cap(i));
+        }
+        return encoderList;
+    }
+
+
+    private EncoderCapabilities() {}  // Don't call me
+
+    // Implemented by JNI
+    private static native final void native_init();
+    private static native final int native_get_num_file_formats();
+    private static native final int native_get_file_format(int index);
+    private static native final int native_get_num_video_encoders();
+    private static native final VideoEncoderCap native_get_video_encoder_cap(int index);
+    private static native final int native_get_num_audio_encoders();
+    private static native final AudioEncoderCap native_get_audio_encoder_cap(int index);
+}
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 1d82e32..d83f493 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -10,7 +10,8 @@
     android_media_MediaRecorder.cpp \
     android_media_MediaScanner.cpp \
     android_media_MediaMetadataRetriever.cpp \
-    android_media_ResampleInputStream.cpp
+    android_media_ResampleInputStream.cpp \
+    android_media_MediaProfiles.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libandroid_runtime \
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 27f5668..76d1674 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -739,6 +739,7 @@
 extern int register_android_media_MediaRecorder(JNIEnv *env);
 extern int register_android_media_MediaScanner(JNIEnv *env);
 extern int register_android_media_ResampleInputStream(JNIEnv *env);
+extern int register_android_media_MediaProfiles(JNIEnv *env);
 
 #ifndef NO_OPENCORE
 extern int register_android_media_AmrInputStream(JNIEnv *env);
@@ -787,6 +788,11 @@
         goto bail;
     }
 
+    if (register_android_media_MediaProfiles(env) < 0) {
+        LOGE("ERROR: MediaProfiles native registration failed");
+        goto bail;
+    }
+
     /* success -- return valid version number */
     result = JNI_VERSION_1_4;
 
diff --git a/media/jni/android_media_MediaProfiles.cpp b/media/jni/android_media_MediaProfiles.cpp
new file mode 100644
index 0000000..cd3ad88
--- /dev/null
+++ b/media/jni/android_media_MediaProfiles.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaProfilesJNI"
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <utils/threads.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include <media/MediaProfiles.h>
+
+using namespace android;
+
+static Mutex sLock;
+MediaProfiles *sProfiles = NULL;
+
+// This function is called from a static block in MediaProfiles.java class,
+// which won't run until the first time an instance of this class is used.
+static void
+android_media_MediaProfiles_native_init(JNIEnv *env)
+{
+    LOGV("native_init");
+    Mutex::Autolock lock(sLock);
+
+    if (sProfiles == NULL) {
+        sProfiles = MediaProfiles::getInstance();
+    }
+}
+
+static int
+android_media_MediaProfiles_native_get_num_file_formats(JNIEnv *env, jobject thiz)
+{
+    LOGV("native_get_num_file_formats");
+    return sProfiles->getOutputFileFormats().size();
+}
+
+static int
+android_media_MediaProfiles_native_get_file_format(JNIEnv *env, jobject thiz, jint index)
+{
+    LOGV("native_get_file_format: %d", index);
+    Vector<output_format> formats = sProfiles->getOutputFileFormats();
+    int nSize = formats.size();
+    if (index < 0 || index >= nSize) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "out of array boundary");
+        return -1;
+    }
+    int format = static_cast<int>(formats[index]);
+    return format;
+}
+
+static int
+android_media_MediaProfiles_native_get_num_video_encoders(JNIEnv *env, jobject thiz)
+{
+    LOGV("native_get_num_video_encoders");
+    return sProfiles->getVideoEncoders().size();
+}
+
+static jobject
+android_media_MediaProfiles_native_get_video_encoder_cap(JNIEnv *env, jobject thiz, jint index)
+{
+    LOGV("native_get_video_encoder_cap: %d", index);
+    Vector<video_encoder> encoders = sProfiles->getVideoEncoders();
+    int nSize = encoders.size();
+    if (index < 0 || index >= nSize) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "out of array boundary");
+        return NULL;
+    }
+
+    video_encoder encoder = encoders[index];
+    int minBitRate = sProfiles->getVideoEncoderParamByName("enc.vid.bps.min", encoder);
+    int maxBitRate = sProfiles->getVideoEncoderParamByName("enc.vid.bps.max", encoder);
+    int minFrameRate = sProfiles->getVideoEncoderParamByName("enc.vid.fps.min", encoder);
+    int maxFrameRate = sProfiles->getVideoEncoderParamByName("enc.vid.fps.max", encoder);
+    int minFrameWidth = sProfiles->getVideoEncoderParamByName("enc.vid.width.min", encoder);
+    int maxFrameWidth = sProfiles->getVideoEncoderParamByName("enc.vid.width.max", encoder);
+    int minFrameHeight = sProfiles->getVideoEncoderParamByName("enc.vid.height.min", encoder);
+    int maxFrameHeight = sProfiles->getVideoEncoderParamByName("enc.vid.height.max", encoder);
+
+    // Check on the values retrieved
+    if ((minBitRate == -1 || maxBitRate == -1) ||
+        (minFrameRate == -1 || maxFrameRate == -1) ||
+        (minFrameWidth == -1 || maxFrameWidth == -1) ||
+        (minFrameHeight == -1 || maxFrameHeight == -1)) {
+
+        jniThrowException(env, "java/lang/RuntimeException", "Error retrieving video encoder capability params");
+        return NULL;
+    }
+
+    // Construct an instance of the VideoEncoderCap and set its member variables
+    jclass videoEncoderCapClazz = env->FindClass("android/media/EncoderCapabilities$VideoEncoderCap");
+    jmethodID videoEncoderCapConstructorMethodID = env->GetMethodID(videoEncoderCapClazz, "<init>", "(IIIIIIIII)V");
+    jobject cap = env->NewObject(videoEncoderCapClazz,
+                                 videoEncoderCapConstructorMethodID,
+                                 static_cast<int>(encoder),
+                                 minBitRate, maxBitRate,
+                                 minFrameRate, maxFrameRate,
+                                 minFrameWidth, maxFrameWidth,
+                                 minFrameHeight, maxFrameHeight);
+    return cap;
+}
+
+static int
+android_media_MediaProfiles_native_get_num_audio_encoders(JNIEnv *env, jobject thiz)
+{
+    LOGV("native_get_num_audio_encoders");
+    return sProfiles->getAudioEncoders().size();
+}
+
+static jobject
+android_media_MediaProfiles_native_get_audio_encoder_cap(JNIEnv *env, jobject thiz, jint index)
+{
+    LOGV("native_get_audio_encoder_cap: %d", index);
+    Vector<audio_encoder> encoders = sProfiles->getAudioEncoders();
+    int nSize = encoders.size();
+    if (index < 0 || index >= nSize) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "out of array boundary");
+        return NULL;
+    }
+
+    audio_encoder encoder = encoders[index];
+    int minBitRate = sProfiles->getAudioEncoderParamByName("enc.aud.bps.min", encoder);
+    int maxBitRate = sProfiles->getAudioEncoderParamByName("enc.aud.bps.max", encoder);
+    int minSampleRate = sProfiles->getAudioEncoderParamByName("enc.aud.hz.min", encoder);
+    int maxSampleRate = sProfiles->getAudioEncoderParamByName("enc.aud.hz.max", encoder);
+    int minChannels = sProfiles->getAudioEncoderParamByName("enc.aud.ch.min", encoder);
+    int maxChannels = sProfiles->getAudioEncoderParamByName("enc.aud.ch.max", encoder);
+
+    // Check on the values retrieved
+    if ((minBitRate == -1 || maxBitRate == -1) ||
+        (minSampleRate == -1 || maxSampleRate == -1) ||
+        (minChannels == -1 || maxChannels == -1)) {
+
+        jniThrowException(env, "java/lang/RuntimeException", "Error retrieving video encoder capability params");
+        return NULL;
+    }
+
+    jclass audioEncoderCapClazz = env->FindClass("android/media/EncoderCapabilities$AudioEncoderCap");
+    jmethodID audioEncoderCapConstructorMethodID = env->GetMethodID(audioEncoderCapClazz, "<init>", "(IIIIIII)V");
+    jobject cap = env->NewObject(audioEncoderCapClazz,
+                                 audioEncoderCapConstructorMethodID,
+                                 static_cast<int>(encoder),
+                                 minBitRate, maxBitRate,
+                                 minSampleRate, maxSampleRate,
+                                 minChannels, maxChannels);
+    return cap;
+}
+
+static JNINativeMethod gMethods[] = {
+    {"native_init",                            "()V",                    (void *)android_media_MediaProfiles_native_init},
+    {"native_get_num_file_formats",            "()I",                    (void *)android_media_MediaProfiles_native_get_num_file_formats},
+    {"native_get_file_format",                 "(I)I",                   (void *)android_media_MediaProfiles_native_get_file_format},
+    {"native_get_num_video_encoders",          "()I",                    (void *)android_media_MediaProfiles_native_get_num_video_encoders},
+    {"native_get_num_audio_encoders",          "()I",                    (void *)android_media_MediaProfiles_native_get_num_audio_encoders},
+
+    {"native_get_video_encoder_cap",           "(I)Landroid/media/EncoderCapabilities$VideoEncoderCap;",
+                                                                         (void *)android_media_MediaProfiles_native_get_video_encoder_cap},
+
+    {"native_get_audio_encoder_cap",           "(I)Landroid/media/EncoderCapabilities$AudioEncoderCap;",
+                                                                         (void *)android_media_MediaProfiles_native_get_audio_encoder_cap},
+};
+
+static const char* const kClassPathName = "android/media/MediaProfiles";
+
+// This function only registers the native methods, and is called from
+// JNI_OnLoad in android_media_MediaPlayer.cpp
+int register_android_media_MediaProfiles(JNIEnv *env)
+{
+    return AndroidRuntime::registerNativeMethods(env,
+                "android/media/EncoderCapabilities", gMethods, NELEM(gMethods));
+}
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 4ae4ec9b..c59d323 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -25,10 +25,11 @@
     MediaScanner.cpp \
     MediaScannerClient.cpp \
     autodetect.cpp \
-    IMediaDeathNotifier.cpp
+    IMediaDeathNotifier.cpp \
+    MediaProfiles.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libui libcutils libutils libbinder libsonivox libicuuc
+	libui libcutils libutils libbinder libsonivox libicuuc libexpat
 
 LOCAL_MODULE:= libmedia
 
@@ -43,10 +44,11 @@
 LOCAL_C_INCLUDES := \
     $(JNI_H_INCLUDE) \
     $(call include-path-for, graphics corecg) \
-        $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
-        external/speex/include \
-        external/speex/libspeex \
-        external/icu4c/common
+    $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
+    external/speex/include \
+    external/speex/libspeex \
+    external/icu4c/common \
+    external/expat/lib
 
 LOCAL_STATIC_LIBRARIES := libspeex
 
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
new file mode 100644
index 0000000..0efade1
--- /dev/null
+++ b/media/libmedia/MediaProfiles.cpp
@@ -0,0 +1,675 @@
+/*
+**
+** Copyright 2010, 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.
+*/
+
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaProfiles"
+
+#include <stdlib.h>
+#include <utils/Log.h>
+#include <utils/Vector.h>
+#include <cutils/properties.h>
+#include <expat.h>
+#include <media/MediaProfiles.h>
+#include <media/stagefright/MediaDebug.h>
+
+namespace android {
+
+Mutex MediaProfiles::sLock;
+bool MediaProfiles::sIsInitialized = false;
+MediaProfiles *MediaProfiles::sInstance = NULL;
+
+const MediaProfiles::NameToTagMap MediaProfiles::sVideoEncoderNameMap[] = {
+    {"h263", VIDEO_ENCODER_H263},
+    {"h264", VIDEO_ENCODER_H264},
+    {"m4v",  VIDEO_ENCODER_MPEG_4_SP}
+};
+
+const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = {
+    {"amrnb", AUDIO_ENCODER_AMR_NB},
+    {"amrwb", AUDIO_ENCODER_AMR_WB},
+    {"aac",   AUDIO_ENCODER_AAC},
+};
+
+const MediaProfiles::NameToTagMap MediaProfiles::sFileFormatMap[] = {
+    {"3gp", OUTPUT_FORMAT_THREE_GPP},
+    {"mp4", OUTPUT_FORMAT_MPEG_4}
+};
+
+const MediaProfiles::NameToTagMap MediaProfiles::sVideoDecoderNameMap[] = {
+    {"wmv", VIDEO_DECODER_WMV}
+};
+
+const MediaProfiles::NameToTagMap MediaProfiles::sAudioDecoderNameMap[] = {
+    {"wma", AUDIO_DECODER_WMA}
+};
+
+const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = {
+    {"high", CAMCORDER_QUALITY_HIGH},
+    {"low",  CAMCORDER_QUALITY_LOW}
+};
+
+/*static*/ void
+MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec)
+{
+    LOGV("video codec:");
+    LOGV("codec = %d", codec.mCodec);
+    LOGV("bit rate: %d", codec.mBitRate);
+    LOGV("frame width: %d", codec.mFrameWidth);
+    LOGV("frame height: %d", codec.mFrameHeight);
+    LOGV("frame rate: %d", codec.mFrameRate);
+}
+
+/*static*/ void
+MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec)
+{
+    LOGV("audio codec:");
+    LOGV("codec = %d", codec.mCodec);
+    LOGV("bit rate: %d", codec.mBitRate);
+    LOGV("sample rate: %d", codec.mSampleRate);
+    LOGV("number of channels: %d", codec.mChannels);
+}
+
+/*static*/ void
+MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap)
+{
+    LOGV("video encoder cap:");
+    LOGV("codec = %d", cap.mCodec);
+    LOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
+    LOGV("frame width: min = %d and max = %d", cap.mMinFrameWidth, cap.mMaxFrameWidth);
+    LOGV("frame height: min = %d and max = %d", cap.mMinFrameHeight, cap.mMaxFrameHeight);
+    LOGV("frame rate: min = %d and max = %d", cap.mMinFrameRate, cap.mMaxFrameRate);
+}
+
+/*static*/ void
+MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap)
+{
+    LOGV("audio encoder cap:");
+    LOGV("codec = %d", cap.mCodec);
+    LOGV("bit rate: min = %d and max = %d", cap.mMinBitRate, cap.mMaxBitRate);
+    LOGV("sample rate: min = %d and max = %d", cap.mMinSampleRate, cap.mMaxSampleRate);
+    LOGV("number of channels: min = %d and max = %d", cap.mMinChannels, cap.mMaxChannels);
+}
+
+/*static*/ void
+MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap)
+{
+    LOGV("video decoder cap:");
+    LOGV("codec = %d", cap.mCodec);
+}
+
+/*static*/ void
+MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap)
+{
+    LOGV("audio codec cap:");
+    LOGV("codec = %d", cap.mCodec);
+}
+
+/*static*/ int
+MediaProfiles::findTagForName(const MediaProfiles::NameToTagMap *map, size_t nMappings, const char *name)
+{
+    int tag = -1;
+    for (size_t i = 0; i < nMappings; ++i) {
+        if (!strcmp(map[i].name, name)) {
+            tag = map[i].tag;
+            break;
+        }
+    }
+    return tag;
+}
+
+/*static*/ MediaProfiles::VideoCodec*
+MediaProfiles::createVideoCodec(const char **atts, MediaProfiles *profiles)
+{
+    CHECK(!strcmp("codec",     atts[0]) &&
+          !strcmp("bitRate",   atts[2]) &&
+          !strcmp("width",     atts[4]) &&
+          !strcmp("height",    atts[6]) &&
+          !strcmp("frameRate", atts[8]));
+
+    const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
+    const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
+    CHECK(codec != -1);
+
+    MediaProfiles::VideoCodec *videoCodec =
+        new MediaProfiles::VideoCodec(static_cast<video_encoder>(codec),
+            atoi(atts[3]), atoi(atts[5]), atoi(atts[7]), atoi(atts[9]));
+    logVideoCodec(*videoCodec);
+
+    size_t nCamcorderProfiles;
+    CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
+    profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mVideoCodec = videoCodec;
+    return videoCodec;
+}
+
+/*static*/ MediaProfiles::AudioCodec*
+MediaProfiles::createAudioCodec(const char **atts, MediaProfiles *profiles)
+{
+    CHECK(!strcmp("codec",      atts[0]) &&
+          !strcmp("bitRate",    atts[2]) &&
+          !strcmp("sampleRate", atts[4]) &&
+          !strcmp("channels",   atts[6]));
+    const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
+    const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
+    CHECK(codec != -1);
+
+    MediaProfiles::AudioCodec *audioCodec =
+        new MediaProfiles::AudioCodec(static_cast<audio_encoder>(codec),
+            atoi(atts[3]), atoi(atts[5]), atoi(atts[7]));
+    logAudioCodec(*audioCodec);
+
+    size_t nCamcorderProfiles;
+    CHECK((nCamcorderProfiles = profiles->mCamcorderProfiles.size()) >= 1);
+    profiles->mCamcorderProfiles[nCamcorderProfiles - 1]->mAudioCodec = audioCodec;
+    return audioCodec;
+}
+/*static*/ MediaProfiles::AudioDecoderCap*
+MediaProfiles::createAudioDecoderCap(const char **atts)
+{
+    CHECK(!strcmp("name",    atts[0]) &&
+          !strcmp("enabled", atts[2]));
+
+    const size_t nMappings = sizeof(sAudioDecoderNameMap)/sizeof(sAudioDecoderNameMap[0]);
+    const int codec = findTagForName(sAudioDecoderNameMap, nMappings, atts[1]);
+    CHECK(codec != -1);
+
+    MediaProfiles::AudioDecoderCap *cap =
+        new MediaProfiles::AudioDecoderCap(static_cast<audio_decoder>(codec));
+    logAudioDecoderCap(*cap);
+    return cap;
+}
+
+/*static*/ MediaProfiles::VideoDecoderCap*
+MediaProfiles::createVideoDecoderCap(const char **atts)
+{
+    CHECK(!strcmp("name",    atts[0]) &&
+          !strcmp("enabled", atts[2]));
+
+    const size_t nMappings = sizeof(sVideoDecoderNameMap)/sizeof(sVideoDecoderNameMap[0]);
+    const int codec = findTagForName(sVideoDecoderNameMap, nMappings, atts[1]);
+    CHECK(codec != -1);
+
+    MediaProfiles::VideoDecoderCap *cap =
+        new MediaProfiles::VideoDecoderCap(static_cast<video_decoder>(codec));
+    logVideoDecoderCap(*cap);
+    return cap;
+}
+
+/*static*/ MediaProfiles::VideoEncoderCap*
+MediaProfiles::createVideoEncoderCap(const char **atts)
+{
+    CHECK(!strcmp("name",           atts[0])  &&
+          !strcmp("enabled",        atts[2])  &&
+          !strcmp("minBitRate",     atts[4])  &&
+          !strcmp("maxBitRate",     atts[6])  &&
+          !strcmp("minFrameWidth",  atts[8])  &&
+          !strcmp("maxFrameWidth",  atts[10]) &&
+          !strcmp("minFrameHeight", atts[12]) &&
+          !strcmp("maxFrameHeight", atts[14]) &&
+          !strcmp("minFrameRate",   atts[16]) &&
+          !strcmp("maxFrameRate",   atts[18]));
+
+    const size_t nMappings = sizeof(sVideoEncoderNameMap)/sizeof(sVideoEncoderNameMap[0]);
+    const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
+    CHECK(codec != -1);
+
+    MediaProfiles::VideoEncoderCap *cap =
+        new MediaProfiles::VideoEncoderCap(static_cast<video_encoder>(codec),
+            atoi(atts[5]), atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
+            atoi(atts[15]), atoi(atts[17]), atoi(atts[19]));
+    logVideoEncoderCap(*cap);
+    return cap;
+}
+
+/*static*/ MediaProfiles::AudioEncoderCap*
+MediaProfiles::createAudioEncoderCap(const char **atts)
+{
+    CHECK(!strcmp("name",          atts[0])  &&
+          !strcmp("enabled",       atts[2])  &&
+          !strcmp("minBitRate",    atts[4])  &&
+          !strcmp("maxBitRate",    atts[6])  &&
+          !strcmp("minSampleRate", atts[8])  &&
+          !strcmp("maxSampleRate", atts[10]) &&
+          !strcmp("minChannels",   atts[12]) &&
+          !strcmp("maxChannels",   atts[14]));
+
+    const size_t nMappings = sizeof(sAudioEncoderNameMap)/sizeof(sAudioEncoderNameMap[0]);
+    const int codec = findTagForName(sAudioEncoderNameMap, nMappings, atts[1]);
+    CHECK(codec != -1);
+
+    MediaProfiles::AudioEncoderCap *cap =
+        new MediaProfiles::AudioEncoderCap(static_cast<audio_encoder>(codec), atoi(atts[5]), atoi(atts[7]),
+            atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
+            atoi(atts[15]));
+    logAudioEncoderCap(*cap);
+    return cap;
+}
+
+/*static*/ output_format
+MediaProfiles::createEncoderOutputFileFormat(const char **atts)
+{
+    CHECK(!strcmp("name", atts[0]));
+
+    const size_t nMappings =sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
+    const int format = findTagForName(sFileFormatMap, nMappings, atts[1]);
+    CHECK(format != -1);
+
+    return static_cast<output_format>(format);
+}
+
+/*static*/ MediaProfiles::CamcorderProfile*
+MediaProfiles::createCamcorderProfile(const char **atts)
+{
+    CHECK(!strcmp("quality",    atts[0]) &&
+          !strcmp("fileFormat", atts[2]) &&
+          !strcmp("duration",   atts[4]));
+
+    const size_t nProfileMappings = sizeof(sCamcorderQualityNameMap)/sizeof(sCamcorderQualityNameMap[0]);
+    const int quality = findTagForName(sCamcorderQualityNameMap, nProfileMappings, atts[1]);
+    CHECK(quality != -1);
+
+    const size_t nFormatMappings = sizeof(sFileFormatMap)/sizeof(sFileFormatMap[0]);
+    const int fileFormat = findTagForName(sFileFormatMap, nFormatMappings, atts[3]);
+    CHECK(fileFormat != -1);
+
+    MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
+    profile->mFileFormat = static_cast<output_format>(fileFormat);
+    profile->mQuality = static_cast<camcorder_quality>(quality);
+    profile->mDuration = atoi(atts[5]);
+    return profile;
+}
+
+/*static*/ void
+MediaProfiles::startElementHandler(void *userData, const char *name, const char **atts)
+{
+    MediaProfiles *profiles = (MediaProfiles *) userData;
+    if (strcmp("Video", name) == 0) {
+        createVideoCodec(atts, profiles);
+    } else if (strcmp("Audio", name) == 0) {
+        createAudioCodec(atts, profiles);
+    } else if (strcmp("VideoEncoderCap", name) == 0 &&
+               strcmp("true", atts[3]) == 0) {
+        profiles->mVideoEncoders.add(createVideoEncoderCap(atts));
+    } else if (strcmp("AudioEncoderCap", name) == 0 &&
+               strcmp("true", atts[3]) == 0) {
+        profiles->mAudioEncoders.add(createAudioEncoderCap(atts));
+    } else if (strcmp("VideoDecoderCap", name) == 0 &&
+               strcmp("true", atts[3]) == 0) {
+        profiles->mVideoDecoders.add(createVideoDecoderCap(atts));
+    } else if (strcmp("AudioDecoderCap", name) == 0 &&
+               strcmp("true", atts[3]) == 0) {
+        profiles->mAudioDecoders.add(createAudioDecoderCap(atts));
+    } else if (strcmp("EncoderOutputFileFormat", name) == 0) {
+        profiles->mEncoderOutputFileFormats.add(createEncoderOutputFileFormat(atts));
+    } else if (strcmp("EncoderProfile", name) == 0) {
+        profiles->mCamcorderProfiles.add(createCamcorderProfile(atts));
+    }
+}
+
+/*static*/ MediaProfiles*
+MediaProfiles::getInstance()
+{
+    LOGV("getInstance");
+    Mutex::Autolock lock(sLock);
+    if (!sIsInitialized) {
+        char value[PROPERTY_VALUE_MAX];
+        if (property_get("media.settings.xml", value, NULL) <= 0) {
+            const char *defaultXmlFile = "/etc/media_profiles.xml";
+            FILE *fp = fopen(defaultXmlFile, "r");
+            if (fp == NULL) {
+                LOGW("could not find media config xml file");
+                sInstance = createDefaultInstance();
+            } else {
+                fclose(fp);  // close the file first.
+                sInstance = createInstanceFromXmlFile(defaultXmlFile);
+            }
+        } else {
+            sInstance = createInstanceFromXmlFile(value);
+        }
+    }
+
+    return sInstance;
+}
+
+/*static*/ MediaProfiles::VideoEncoderCap*
+MediaProfiles::createDefaultH263VideoEncoderCap()
+{
+    return new MediaProfiles::VideoEncoderCap(
+        VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20);
+}
+
+/*static*/ MediaProfiles::VideoEncoderCap*
+MediaProfiles::createDefaultM4vVideoEncoderCap()
+{
+    return new MediaProfiles::VideoEncoderCap(
+        VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20);
+}
+
+
+/*static*/ void
+MediaProfiles::createDefaultVideoEncoders(MediaProfiles *profiles)
+{
+    profiles->mVideoEncoders.add(createDefaultH263VideoEncoderCap());
+    profiles->mVideoEncoders.add(createDefaultM4vVideoEncoderCap());
+}
+
+/*static*/ MediaProfiles::CamcorderProfile*
+MediaProfiles::createDefaultCamcorderHighProfile()
+{
+    MediaProfiles::VideoCodec *videoCodec =
+        new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 360000, 352, 288, 20);
+
+    AudioCodec *audioCodec = new AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
+    CamcorderProfile *profile = new CamcorderProfile;
+    profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
+    profile->mQuality = CAMCORDER_QUALITY_HIGH;
+    profile->mDuration = 60;
+    profile->mVideoCodec = videoCodec;
+    profile->mAudioCodec = audioCodec;
+    return profile;
+}
+
+/*static*/ MediaProfiles::CamcorderProfile*
+MediaProfiles::createDefaultCamcorderLowProfile()
+{
+    MediaProfiles::VideoCodec *videoCodec =
+        new MediaProfiles::VideoCodec(VIDEO_ENCODER_H263, 192000, 176, 144, 20);
+
+    MediaProfiles::AudioCodec *audioCodec =
+        new MediaProfiles::AudioCodec(AUDIO_ENCODER_AMR_NB, 12200, 8000, 1);
+
+    MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
+    profile->mFileFormat = OUTPUT_FORMAT_THREE_GPP;
+    profile->mQuality = CAMCORDER_QUALITY_LOW;
+    profile->mDuration = 30;
+    profile->mVideoCodec = videoCodec;
+    profile->mAudioCodec = audioCodec;
+    return profile;
+}
+
+/*static*/ void
+MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles)
+{
+    profiles->mCamcorderProfiles.add(createDefaultCamcorderHighProfile());
+    profiles->mCamcorderProfiles.add(createDefaultCamcorderLowProfile());
+}
+
+/*static*/ void
+MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
+{
+    profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
+}
+
+/*static*/ void
+MediaProfiles::createDefaultVideoDecoders(MediaProfiles *profiles)
+{
+    MediaProfiles::VideoDecoderCap *cap =
+        new MediaProfiles::VideoDecoderCap(VIDEO_DECODER_WMV);
+
+    profiles->mVideoDecoders.add(cap);
+}
+
+/*static*/ void
+MediaProfiles::createDefaultAudioDecoders(MediaProfiles *profiles)
+{
+    MediaProfiles::AudioDecoderCap *cap =
+        new MediaProfiles::AudioDecoderCap(AUDIO_DECODER_WMA);
+
+    profiles->mAudioDecoders.add(cap);
+}
+
+/*static*/ void
+MediaProfiles::createDefaultEncoderOutputFileFormats(MediaProfiles *profiles)
+{
+    profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_THREE_GPP);
+    profiles->mEncoderOutputFileFormats.add(OUTPUT_FORMAT_MPEG_4);
+}
+
+/*static*/ MediaProfiles::AudioEncoderCap*
+MediaProfiles::createDefaultAmrNBEncoderCap()
+{
+    return new MediaProfiles::AudioEncoderCap(
+        AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
+}
+
+/*static*/ MediaProfiles*
+MediaProfiles::createDefaultInstance()
+{
+    MediaProfiles *profiles = new MediaProfiles;
+    createDefaultCamcorderProfiles(profiles);
+    createDefaultVideoEncoders(profiles);
+    createDefaultAudioEncoders(profiles);
+    createDefaultVideoDecoders(profiles);
+    createDefaultAudioDecoders(profiles);
+    createDefaultEncoderOutputFileFormats(profiles);
+    sIsInitialized = true;
+    return profiles;
+}
+
+/*static*/ MediaProfiles*
+MediaProfiles::createInstanceFromXmlFile(const char *xml)
+{
+    FILE *fp = NULL;
+    CHECK((fp = fopen(xml, "r")));
+
+    XML_Parser parser = ::XML_ParserCreate(NULL);
+    CHECK(parser != NULL);
+
+    MediaProfiles *profiles = new MediaProfiles();
+    ::XML_SetUserData(parser, profiles);
+    ::XML_SetElementHandler(parser, startElementHandler, NULL);
+
+    /*
+      FIXME:
+      expat is not compiled with -DXML_DTD. We don't have DTD parsing support.
+
+      if (!::XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)) {
+          LOGE("failed to enable DTD support in the xml file");
+          return UNKNOWN_ERROR;
+      }
+
+    */
+
+    const int BUFF_SIZE = 512;
+    for (;;) {
+        void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
+        if (buff == NULL) {
+            LOGE("failed to in call to XML_GetBuffer()");
+            delete profiles;
+            profiles = NULL;
+            goto exit;
+        }
+
+        int bytes_read = ::fread(buff, 1, BUFF_SIZE, fp);
+        if (bytes_read < 0) {
+            LOGE("failed in call to read");
+            delete profiles;
+            profiles = NULL;
+            goto exit;
+        }
+
+        CHECK(::XML_ParseBuffer(parser, bytes_read, bytes_read == 0));
+
+        if (bytes_read == 0) break;  // done parsing the xml file
+    }
+
+exit:
+    ::XML_ParserFree(parser);
+    ::fclose(fp);
+    if (profiles) {
+        sIsInitialized = true;
+    }
+    return profiles;
+}
+
+Vector<output_format> MediaProfiles::getOutputFileFormats() const
+{
+    return mEncoderOutputFileFormats;  // copy out
+}
+
+Vector<video_encoder> MediaProfiles::getVideoEncoders() const
+{
+    Vector<video_encoder> encoders;
+    for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
+        encoders.add(mVideoEncoders[i]->mCodec);
+    }
+    return encoders;  // copy out
+}
+
+int MediaProfiles::getVideoEncoderParamByName(const char *name, video_encoder codec) const
+{
+    LOGV("getVideoEncoderParamByName: %s for codec %d", name, codec);
+    int index = -1;
+    for (size_t i = 0, n = mVideoEncoders.size(); i < n; ++i) {
+        if (mVideoEncoders[i]->mCodec == codec) {
+            index = i;
+            break;
+        }
+    }
+    if (index == -1) {
+        LOGE("The given video encoder %d is not found", codec);
+        return -1;
+    }
+
+    if (!strcmp("enc.vid.width.min", name)) return mVideoEncoders[index]->mMinFrameWidth;
+    if (!strcmp("enc.vid.width.max", name)) return mVideoEncoders[index]->mMaxFrameWidth;
+    if (!strcmp("enc.vid.height.min", name)) return mVideoEncoders[index]->mMinFrameHeight;
+    if (!strcmp("enc.vid.height.max", name)) return mVideoEncoders[index]->mMaxFrameHeight;
+    if (!strcmp("enc.vid.bps.min", name)) return mVideoEncoders[index]->mMinBitRate;
+    if (!strcmp("enc.vid.bps.max", name)) return mVideoEncoders[index]->mMaxBitRate;
+    if (!strcmp("enc.vid.fps.min", name)) return mVideoEncoders[index]->mMinFrameRate;
+    if (!strcmp("enc.vid.fps.max", name)) return mVideoEncoders[index]->mMaxFrameRate;
+
+    LOGE("The given video encoder param name %s is not found", name);
+    return -1;
+}
+
+Vector<audio_encoder> MediaProfiles::getAudioEncoders() const
+{
+    Vector<audio_encoder> encoders;
+    for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
+        encoders.add(mAudioEncoders[i]->mCodec);
+    }
+    return encoders;  // copy out
+}
+
+int MediaProfiles::getAudioEncoderParamByName(const char *name, audio_encoder codec) const
+{
+    LOGV("getAudioEncoderParamByName: %s for codec %d", name, codec);
+    int index = -1;
+    for (size_t i = 0, n = mAudioEncoders.size(); i < n; ++i) {
+        if (mAudioEncoders[i]->mCodec == codec) {
+            index = i;
+            break;
+        }
+    }
+    if (index == -1) {
+        LOGE("The given audio encoder %d is not found", codec);
+        return -1;
+    }
+
+    if (!strcmp("enc.aud.ch.min", name)) return mAudioEncoders[index]->mMinChannels;
+    if (!strcmp("enc.aud.ch.max", name)) return mAudioEncoders[index]->mMaxChannels;
+    if (!strcmp("enc.aud.bps.min", name)) return mAudioEncoders[index]->mMinBitRate;
+    if (!strcmp("enc.aud.bps.max", name)) return mAudioEncoders[index]->mMaxBitRate;
+    if (!strcmp("enc.aud.hz.min", name)) return mAudioEncoders[index]->mMinSampleRate;
+    if (!strcmp("enc.aud.hz.max", name)) return mAudioEncoders[index]->mMaxSampleRate;
+
+    LOGE("The given audio encoder param name %s is not found", name);
+    return -1;
+}
+
+Vector<video_decoder> MediaProfiles::getVideoDecoders() const
+{
+    Vector<video_decoder> decoders;
+    for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
+        decoders.add(mVideoDecoders[i]->mCodec);
+    }
+    return decoders;  // copy out
+}
+
+Vector<audio_decoder> MediaProfiles::getAudioDecoders() const
+{
+    Vector<audio_decoder> decoders;
+    for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
+        decoders.add(mAudioDecoders[i]->mCodec);
+    }
+    return decoders;  // copy out
+}
+
+int MediaProfiles::getCamcorderProfileParamByName(const char *name, camcorder_quality quality) const
+{
+    LOGV("getCamcorderProfileParamByName: %s for quality %d", name, quality);
+
+    int index = -1;
+    for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
+        if (mCamcorderProfiles[i]->mQuality == quality) {
+            index = i;
+            break;
+        }
+    }
+    if (index == -1) {
+        LOGE("The given camcorder profile quality %d is not found", quality);
+        return -1;
+    }
+
+    if (!strcmp("file.format", name)) return mCamcorderProfiles[index]->mFileFormat;
+    if (!strcmp("vid.codec", name)) return mCamcorderProfiles[index]->mVideoCodec->mCodec;
+    if (!strcmp("vid.width", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameWidth;
+    if (!strcmp("vid.height", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameHeight;
+    if (!strcmp("vid.bps", name)) return mCamcorderProfiles[index]->mVideoCodec->mBitRate;
+    if (!strcmp("vid.fps", name)) return mCamcorderProfiles[index]->mVideoCodec->mFrameRate;
+    if (!strcmp("aud.codec", name)) return mCamcorderProfiles[index]->mAudioCodec->mCodec;
+    if (!strcmp("aud.bps", name)) return mCamcorderProfiles[index]->mAudioCodec->mBitRate;
+    if (!strcmp("aud.ch", name)) return mCamcorderProfiles[index]->mAudioCodec->mChannels;
+    if (!strcmp("aud.hz", name)) return mCamcorderProfiles[index]->mAudioCodec->mSampleRate;
+
+    LOGE("The given camcorder profile param name %s is not found", name);
+    return -1;
+}
+
+MediaProfiles::~MediaProfiles()
+{
+    CHECK("destructor should never be called" == 0);
+#if 0
+    for (size_t i = 0; i < mAudioEncoders.size(); ++i) {
+        delete mAudioEncoders[i];
+    }
+    mAudioEncoders.clear();
+
+    for (size_t i = 0; i < mVideoEncoders.size(); ++i) {
+        delete mVideoEncoders[i];
+    }
+    mVideoEncoders.clear();
+
+    for (size_t i = 0; i < mVideoDecoders.size(); ++i) {
+        delete mVideoDecoders[i];
+    }
+    mVideoDecoders.clear();
+
+    for (size_t i = 0; i < mAudioDecoders.size(); ++i) {
+        delete mAudioDecoders[i];
+    }
+    mAudioDecoders.clear();
+
+    for (size_t i = 0; i < mCamcorderProfiles.size(); ++i) {
+        delete mCamcorderProfiles[i];
+    }
+    mCamcorderProfiles.clear();
+#endif
+}
+} // namespace android