diff --git a/android-16.0.0_r2/external/minijail/0001-disable-seccomp.patch b/android-16.0.0_r2/external/minijail/0001-disable-seccomp.patch new file mode 100644 index 0000000..6bce8b5 --- /dev/null +++ b/android-16.0.0_r2/external/minijail/0001-disable-seccomp.patch @@ -0,0 +1,32 @@ +From d0a81eab5bafdc3f446d921965a0fd555abe4170 Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Mon, 26 Apr 2021 22:55:03 +0800 +Subject: [PATCH] disable seccomp + +--- + libminijail.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/libminijail.c b/libminijail.c +index de59b8a..15016a1 100644 +--- a/libminijail.c ++++ b/libminijail.c +@@ -2702,6 +2702,7 @@ static void set_seccomp_filter(const struct minijail *j) + /* + * Install the syscall filter. + */ ++#if 0 // HACKED + if (j->flags.seccomp_filter) { + if (j->flags.seccomp_filter_tsync || + j->flags.seccomp_filter_allow_speculation) { +@@ -2723,6 +2724,7 @@ static void set_seccomp_filter(const struct minijail *j) + } + } + } ++#endif + } + + static pid_t forward_pid = -1; +-- +2.49.0 + diff --git a/android-16.0.0_r2/external/selinux/0001-ignore-selinux.patch b/android-16.0.0_r2/external/selinux/0001-ignore-selinux.patch new file mode 100644 index 0000000..8d57b1b --- /dev/null +++ b/android-16.0.0_r2/external/selinux/0001-ignore-selinux.patch @@ -0,0 +1,165 @@ +From a35002efe9fb08f04e6ddeb4c986d8498a140119 Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Sun, 9 May 2021 23:44:12 +0800 +Subject: [PATCH] ignore selinux + +--- + libselinux/include/selinux/selinux.h | 4 ++++ + libselinux/src/checkAccess.c | 1 + + libselinux/src/getenforce.c | 1 + + libselinux/src/getfilecon.c | 1 + + libselinux/src/getpeercon.c | 1 + + libselinux/src/init.c | 1 + + libselinux/src/label.c | 1 + + libselinux/src/lgetfilecon.c | 1 + + libselinux/src/lsetfilecon.c | 1 + + libselinux/src/procattr.c | 2 ++ + libselinux/src/sestatus.c | 1 + + 11 files changed, 15 insertions(+) + +diff --git a/libselinux/include/selinux/selinux.h b/libselinux/include/selinux/selinux.h +index 50419a7..01e4a3f 100644 +--- a/libselinux/include/selinux/selinux.h ++++ b/libselinux/include/selinux/selinux.h +@@ -4,6 +4,10 @@ + #include + #include + ++#define SE_HACK ++#define se_hack() if (1) return ++#define se_hack1(p) if (1) return p ++ + #ifdef __cplusplus + extern "C" { + #endif +diff --git a/libselinux/src/checkAccess.c b/libselinux/src/checkAccess.c +index 022cd6b..a23bffc 100644 +--- a/libselinux/src/checkAccess.c ++++ b/libselinux/src/checkAccess.c +@@ -20,6 +20,7 @@ static void avc_init_once(void) + } + + int selinux_check_access(const char *scon, const char *tcon, const char *class, const char *perm, void *aux) { ++ se_hack1(0); + int rc; + security_id_t scon_id; + security_id_t tcon_id; +diff --git a/libselinux/src/getenforce.c b/libselinux/src/getenforce.c +index 3f1e200..bf16227 100644 +--- a/libselinux/src/getenforce.c ++++ b/libselinux/src/getenforce.c +@@ -11,6 +11,7 @@ + + int security_getenforce(void) + { ++ se_hack1(0); + int fd, ret, enforce = 0; + char path[PATH_MAX]; + char buf[20]; +diff --git a/libselinux/src/getfilecon.c b/libselinux/src/getfilecon.c +index 4bee313..f8b159a 100644 +--- a/libselinux/src/getfilecon.c ++++ b/libselinux/src/getfilecon.c +@@ -52,6 +52,7 @@ int getfilecon_raw(const char *path, char ** context) + + int getfilecon(const char *path, char ** context) + { ++ se_hack1((*context = calloc(7, 1), memcpy(*context, "HACKED", 6), 0)); + int ret; + char * rcontext = NULL; + +diff --git a/libselinux/src/getpeercon.c b/libselinux/src/getpeercon.c +index a9dca73..10771cb 100644 +--- a/libselinux/src/getpeercon.c ++++ b/libselinux/src/getpeercon.c +@@ -46,6 +46,7 @@ int getpeercon_raw(int fd, char ** context) + + int getpeercon(int fd, char ** context) + { ++ se_hack1((*context = calloc(7, 1), memcpy(*context, "HACKED", 6), 0)); + int ret; + char * rcontext; + +diff --git a/libselinux/src/init.c b/libselinux/src/init.c +index 439da41..41268a7 100644 +--- a/libselinux/src/init.c ++++ b/libselinux/src/init.c +@@ -139,6 +139,7 @@ void fini_selinuxmnt(void) + + void set_selinuxmnt(const char *mnt) + { ++ se_hack(); + selinux_mnt = strdup(mnt); + } + +diff --git a/libselinux/src/label.c b/libselinux/src/label.c +index 08bbac2..c87f05a 100644 +--- a/libselinux/src/label.c ++++ b/libselinux/src/label.c +@@ -303,6 +303,7 @@ bool selabel_hash_all_partial_matches(struct selabel_handle *rec, + int selabel_lookup_best_match(struct selabel_handle *rec, char **con, + const char *key, const char **aliases, int type) + { ++ se_hack1((*con = calloc(7, 1), memcpy(*con, "HACKED", 6), 0)); + struct selabel_lookup_rec *lr; + + if (!rec->func_lookup_best_match) { +diff --git a/libselinux/src/lgetfilecon.c b/libselinux/src/lgetfilecon.c +index d1fb821..0d3b0ac 100644 +--- a/libselinux/src/lgetfilecon.c ++++ b/libselinux/src/lgetfilecon.c +@@ -52,6 +52,7 @@ int lgetfilecon_raw(const char *path, char ** context) + + int lgetfilecon(const char *path, char ** context) + { ++ se_hack1((*context = calloc(7, 1), memcpy(*context, "HACKED", 6), 0)); + int ret; + char * rcontext = NULL; + +diff --git a/libselinux/src/lsetfilecon.c b/libselinux/src/lsetfilecon.c +index 213fb68..c73c152 100644 +--- a/libselinux/src/lsetfilecon.c ++++ b/libselinux/src/lsetfilecon.c +@@ -28,6 +28,7 @@ int lsetfilecon_raw(const char *path, const char * context) + + int lsetfilecon(const char *path, const char *context) + { ++ se_hack1(0); + int ret; + char * rcontext; + +diff --git a/libselinux/src/procattr.c b/libselinux/src/procattr.c +index b7a93a2..a1478c7 100644 +--- a/libselinux/src/procattr.c ++++ b/libselinux/src/procattr.c +@@ -175,6 +175,7 @@ static int getprocattrcon_raw(char **context, pid_t pid, const char *attr, + static int getprocattrcon(char **context, pid_t pid, const char *attr, + const char *prev_context) + { ++ se_hack1((*context = calloc(7, 1), memcpy(*context, "HACKED", 6), 0)); + int ret; + char * rcontext; + +@@ -239,6 +240,7 @@ out: + static int setprocattrcon(const char *context, const char *attr, + char **prev_context) + { ++ se_hack1(0); + int ret; + char * rcontext; + +diff --git a/libselinux/src/sestatus.c b/libselinux/src/sestatus.c +index fbe6430..bafe6bb 100644 +--- a/libselinux/src/sestatus.c ++++ b/libselinux/src/sestatus.c +@@ -277,6 +277,7 @@ static int fallback_cb_policyload(int policyload) + */ + int selinux_status_open(int fallback) + { ++ se_hack1(0); + int fd; + char path[PATH_MAX]; + long pagesize; +-- +2.49.0 + diff --git a/android-16.0.0_r2/frameworks/av/0001-workaround-for-mesa-video-playback.patch b/android-16.0.0_r2/frameworks/av/0001-workaround-for-mesa-video-playback.patch new file mode 100644 index 0000000..8a735a6 --- /dev/null +++ b/android-16.0.0_r2/frameworks/av/0001-workaround-for-mesa-video-playback.patch @@ -0,0 +1,48 @@ +From 955729e06e1e47a7c62a4b40c347ddf6f6d0001c Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Mon, 20 Sep 2021 18:22:20 +0000 +Subject: [PATCH 1/2] ? workaround for mesa video playback + +--- + media/libstagefright/colorconversion/SoftwareRenderer.cpp | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp +index 2409315..1e3ec7b 100644 +--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp ++++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp +@@ -130,6 +130,7 @@ void SoftwareRenderer::resetFormatIfChanged( + // hardware has YUV12 and RGBA8888 support, so convert known formats + { + switch (mColorFormat) { ++#if 0 // HACKED + case OMX_COLOR_FormatYUV420Planar: + case OMX_COLOR_FormatYUV420SemiPlanar: + case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: +@@ -139,6 +140,7 @@ void SoftwareRenderer::resetFormatIfChanged( + bufHeight = (mCropHeight + 1) & ~1; + break; + } ++#endif + case OMX_COLOR_Format24bitRGB888: + { + halFormat = HAL_PIXEL_FORMAT_RGB_888; +@@ -154,6 +156,7 @@ void SoftwareRenderer::resetFormatIfChanged( + bufHeight = (mCropHeight + 1) & ~1; + break; + } ++#if 0 // HACKED + case OMX_COLOR_FormatYUV420Planar16: + { + if (((dataSpace & HAL_DATASPACE_STANDARD_MASK) == HAL_DATASPACE_STANDARD_BT2020) +@@ -170,6 +173,7 @@ void SoftwareRenderer::resetFormatIfChanged( + bufHeight = (mCropHeight + 1) & ~1; + break; + } ++#endif + default: + { + break; +-- +2.49.0 + diff --git a/android-16.0.0_r2/frameworks/av/0002-bring-back-OMX.patch b/android-16.0.0_r2/frameworks/av/0002-bring-back-OMX.patch new file mode 100644 index 0000000..653cd6a --- /dev/null +++ b/android-16.0.0_r2/frameworks/av/0002-bring-back-OMX.patch @@ -0,0 +1,22408 @@ +From 26fd52895688f7e4d583ab25a1fe2b15451bdb3b Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Tue, 24 Jun 2025 23:26:59 +0800 +Subject: [PATCH 2/2] bring back OMX + +Change-Id: I41ad31958a4b9dd83a3c3e531bfdb3db94bcb693 +--- + media/libstagefright/codecs/aacdec/Android.bp | 44 + + .../codecs/aacdec/DrcPresModeWrap.cpp | 371 ++++ + .../codecs/aacdec/DrcPresModeWrap.h | 62 + + .../codecs/aacdec/MODULE_LICENSE_APACHE2 | 0 + media/libstagefright/codecs/aacdec/NOTICE | 190 ++ + .../libstagefright/codecs/aacdec/SoftAAC2.cpp | 1255 ++++++++++++ + media/libstagefright/codecs/aacdec/SoftAAC2.h | 109 ++ + .../libstagefright/codecs/aacdec/exports.lds | 5 + + media/libstagefright/codecs/aacenc/Android.bp | 37 + + .../codecs/aacenc/MODULE_LICENSE_APACHE2 | 0 + media/libstagefright/codecs/aacenc/NOTICE | 190 ++ + .../codecs/aacenc/SoftAACEncoder2.cpp | 740 +++++++ + .../codecs/aacenc/SoftAACEncoder2.h | 82 + + .../libstagefright/codecs/aacenc/exports.lds | 5 + + .../codecs/aacenc/patent_disclaimer.txt | 9 + + .../codecs/amrnb/dec/Android.bp | 39 + + .../codecs/amrnb/dec/SoftAMR.cpp | 585 ++++++ + .../libstagefright/codecs/amrnb/dec/SoftAMR.h | 91 + + .../codecs/amrnb/dec/exports.lds | 5 + + .../codecs/amrnb/enc/Android.bp | 31 + + .../codecs/amrnb/enc/SoftAMRNBEncoder.cpp | 429 +++++ + .../codecs/amrnb/enc/SoftAMRNBEncoder.h | 72 + + .../codecs/amrnb/enc/exports.lds | 5 + + .../libstagefright/codecs/amrwbenc/Android.bp | 31 + + .../codecs/amrwbenc/SoftAMRWBEncoder.cpp | 484 +++++ + .../codecs/amrwbenc/SoftAMRWBEncoder.h | 76 + + .../codecs/amrwbenc/exports.lds | 5 + + media/libstagefright/codecs/avcdec/Android.bp | 34 + + .../codecs/avcdec/SoftAVCDec.cpp | 732 +++++++ + .../libstagefright/codecs/avcdec/SoftAVCDec.h | 168 ++ + .../libstagefright/codecs/avcdec/exports.lds | 5 + + media/libstagefright/codecs/avcenc/Android.bp | 34 + + .../codecs/avcenc/SoftAVCEnc.cpp | 1515 +++++++++++++++ + .../libstagefright/codecs/avcenc/SoftAVCEnc.h | 317 +++ + .../libstagefright/codecs/avcenc/exports.lds | 5 + + .../libstagefright/codecs/flac/dec/Android.bp | 41 + + .../codecs/flac/dec/MODULE_LICENSE_APACHE2 | 0 + media/libstagefright/codecs/flac/dec/NOTICE | 190 ++ + .../codecs/flac/dec/SoftFlacDecoder.cpp | 500 +++++ + .../codecs/flac/dec/SoftFlacDecoder.h | 81 + + .../codecs/flac/dec/exports.lds | 5 + + .../libstagefright/codecs/flac/enc/Android.bp | 43 + + .../codecs/flac/enc/MODULE_LICENSE_APACHE2 | 0 + media/libstagefright/codecs/flac/enc/NOTICE | 190 ++ + .../codecs/flac/enc/SoftFlacEncoder.cpp | 601 ++++++ + .../codecs/flac/enc/SoftFlacEncoder.h | 101 + + .../codecs/flac/enc/exports.lds | 5 + + .../libstagefright/codecs/g711/dec/Android.bp | 35 + + .../codecs/g711/dec/MODULE_LICENSE_APACHE2 | 0 + media/libstagefright/codecs/g711/dec/NOTICE | 190 ++ + .../codecs/g711/dec/SoftG711.cpp | 391 ++++ + .../libstagefright/codecs/g711/dec/SoftG711.h | 64 + + .../codecs/g711/dec/exports.lds | 5 + + .../libstagefright/codecs/gsm/dec/Android.bp | 37 + + .../codecs/gsm/dec/MODULE_LICENSE_APACHE2 | 0 + media/libstagefright/codecs/gsm/dec/NOTICE | 190 ++ + .../libstagefright/codecs/gsm/dec/SoftGSM.cpp | 363 ++++ + media/libstagefright/codecs/gsm/dec/SoftGSM.h | 66 + + .../libstagefright/codecs/gsm/dec/exports.lds | 5 + + .../libstagefright/codecs/hevcdec/Android.bp | 38 + + .../codecs/hevcdec/SoftHEVC.cpp | 726 +++++++ + .../libstagefright/codecs/hevcdec/SoftHEVC.h | 123 ++ + .../libstagefright/codecs/hevcdec/exports.lds | 5 + + .../codecs/m4v_h263/dec/Android.bp | 28 + + .../codecs/m4v_h263/dec/SoftMPEG4.cpp | 440 +++++ + .../codecs/m4v_h263/dec/SoftMPEG4.h | 79 + + .../codecs/m4v_h263/dec/exports.lds | 5 + + .../codecs/m4v_h263/enc/Android.bp | 30 + + .../codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp | 550 ++++++ + .../codecs/m4v_h263/enc/SoftMPEG4Encoder.h | 88 + + .../codecs/m4v_h263/enc/exports.lds | 5 + + media/libstagefright/codecs/mp3dec/Android.bp | 27 + + .../libstagefright/codecs/mp3dec/SoftMP3.cpp | 506 +++++ + media/libstagefright/codecs/mp3dec/SoftMP3.h | 84 + + .../libstagefright/codecs/mp3dec/exports.lds | 5 + + .../libstagefright/codecs/mpeg2dec/Android.bp | 32 + + .../codecs/mpeg2dec/SoftMPEG2.cpp | 872 +++++++++ + .../codecs/mpeg2dec/SoftMPEG2.h | 184 ++ + .../codecs/mpeg2dec/exports.lds | 5 + + .../libstagefright/codecs/on2/dec/Android.bp | 37 + + .../codecs/on2/dec/MODULE_LICENSE_APACHE2 | 0 + media/libstagefright/codecs/on2/dec/NOTICE | 190 ++ + .../libstagefright/codecs/on2/dec/SoftVPX.cpp | 374 ++++ + media/libstagefright/codecs/on2/dec/SoftVPX.h | 84 + + .../libstagefright/codecs/on2/dec/exports.lds | 5 + + .../libstagefright/codecs/on2/enc/Android.bp | 44 + + .../codecs/on2/enc/MODULE_LICENSE_APACHE2 | 0 + media/libstagefright/codecs/on2/enc/NOTICE | 190 ++ + .../codecs/on2/enc/SoftVP8Encoder.cpp | 172 ++ + .../codecs/on2/enc/SoftVP8Encoder.h | 93 + + .../codecs/on2/enc/SoftVP9Encoder.cpp | 179 ++ + .../codecs/on2/enc/SoftVP9Encoder.h | 91 + + .../codecs/on2/enc/SoftVPXEncoder.cpp | 799 ++++++++ + .../codecs/on2/enc/SoftVPXEncoder.h | 251 +++ + .../libstagefright/codecs/on2/enc/exports.lds | 5 + + .../libstagefright/codecs/opus/dec/Android.bp | 29 + + .../codecs/opus/dec/SoftOpus.cpp | 674 +++++++ + .../libstagefright/codecs/opus/dec/SoftOpus.h | 98 + + .../codecs/opus/dec/exports.lds | 5 + + media/libstagefright/codecs/raw/Android.bp | 35 + + .../codecs/raw/MODULE_LICENSE_APACHE2 | 0 + media/libstagefright/codecs/raw/NOTICE | 190 ++ + media/libstagefright/codecs/raw/SoftRaw.cpp | 281 +++ + media/libstagefright/codecs/raw/SoftRaw.h | 64 + + media/libstagefright/codecs/raw/exports.lds | 5 + + .../codecs/vorbis/dec/Android.bp | 38 + + .../codecs/vorbis/dec/MODULE_LICENSE_APACHE2 | 0 + media/libstagefright/codecs/vorbis/dec/NOTICE | 190 ++ + .../codecs/vorbis/dec/SoftVorbis.cpp | 644 +++++++ + .../codecs/vorbis/dec/SoftVorbis.h | 83 + + .../codecs/vorbis/dec/exports.lds | 5 + + .../libstagefright/codecs/xaacdec/Android.bp | 36 + + .../codecs/xaacdec/SoftXAAC.cpp | 1702 +++++++++++++++++ + .../libstagefright/codecs/xaacdec/SoftXAAC.h | 130 ++ + media/libstagefright/omx/Android.bp | 32 + + media/libstagefright/omx/OMXStore.cpp | 1 - + services/mediacodec/Android.bp | 25 + + 117 files changed, 21477 insertions(+), 1 deletion(-) + create mode 100644 media/libstagefright/codecs/aacdec/Android.bp + create mode 100644 media/libstagefright/codecs/aacdec/DrcPresModeWrap.cpp + create mode 100644 media/libstagefright/codecs/aacdec/DrcPresModeWrap.h + create mode 100644 media/libstagefright/codecs/aacdec/MODULE_LICENSE_APACHE2 + create mode 100644 media/libstagefright/codecs/aacdec/NOTICE + create mode 100644 media/libstagefright/codecs/aacdec/SoftAAC2.cpp + create mode 100644 media/libstagefright/codecs/aacdec/SoftAAC2.h + create mode 100644 media/libstagefright/codecs/aacdec/exports.lds + create mode 100644 media/libstagefright/codecs/aacenc/Android.bp + create mode 100644 media/libstagefright/codecs/aacenc/MODULE_LICENSE_APACHE2 + create mode 100644 media/libstagefright/codecs/aacenc/NOTICE + create mode 100644 media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp + create mode 100644 media/libstagefright/codecs/aacenc/SoftAACEncoder2.h + create mode 100644 media/libstagefright/codecs/aacenc/exports.lds + create mode 100644 media/libstagefright/codecs/aacenc/patent_disclaimer.txt + create mode 100644 media/libstagefright/codecs/amrnb/dec/Android.bp + create mode 100644 media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp + create mode 100644 media/libstagefright/codecs/amrnb/dec/SoftAMR.h + create mode 100644 media/libstagefright/codecs/amrnb/dec/exports.lds + create mode 100644 media/libstagefright/codecs/amrnb/enc/Android.bp + create mode 100644 media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp + create mode 100644 media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h + create mode 100644 media/libstagefright/codecs/amrnb/enc/exports.lds + create mode 100644 media/libstagefright/codecs/amrwbenc/Android.bp + create mode 100644 media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp + create mode 100644 media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h + create mode 100644 media/libstagefright/codecs/amrwbenc/exports.lds + create mode 100644 media/libstagefright/codecs/avcdec/Android.bp + create mode 100644 media/libstagefright/codecs/avcdec/SoftAVCDec.cpp + create mode 100644 media/libstagefright/codecs/avcdec/SoftAVCDec.h + create mode 100644 media/libstagefright/codecs/avcdec/exports.lds + create mode 100644 media/libstagefright/codecs/avcenc/Android.bp + create mode 100644 media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp + create mode 100644 media/libstagefright/codecs/avcenc/SoftAVCEnc.h + create mode 100644 media/libstagefright/codecs/avcenc/exports.lds + create mode 100644 media/libstagefright/codecs/flac/dec/Android.bp + create mode 100644 media/libstagefright/codecs/flac/dec/MODULE_LICENSE_APACHE2 + create mode 100644 media/libstagefright/codecs/flac/dec/NOTICE + create mode 100644 media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp + create mode 100644 media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h + create mode 100644 media/libstagefright/codecs/flac/dec/exports.lds + create mode 100644 media/libstagefright/codecs/flac/enc/Android.bp + create mode 100644 media/libstagefright/codecs/flac/enc/MODULE_LICENSE_APACHE2 + create mode 100644 media/libstagefright/codecs/flac/enc/NOTICE + create mode 100644 media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp + create mode 100644 media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h + create mode 100644 media/libstagefright/codecs/flac/enc/exports.lds + create mode 100644 media/libstagefright/codecs/g711/dec/Android.bp + create mode 100644 media/libstagefright/codecs/g711/dec/MODULE_LICENSE_APACHE2 + create mode 100644 media/libstagefright/codecs/g711/dec/NOTICE + create mode 100644 media/libstagefright/codecs/g711/dec/SoftG711.cpp + create mode 100644 media/libstagefright/codecs/g711/dec/SoftG711.h + create mode 100644 media/libstagefright/codecs/g711/dec/exports.lds + create mode 100644 media/libstagefright/codecs/gsm/dec/Android.bp + create mode 100644 media/libstagefright/codecs/gsm/dec/MODULE_LICENSE_APACHE2 + create mode 100644 media/libstagefright/codecs/gsm/dec/NOTICE + create mode 100644 media/libstagefright/codecs/gsm/dec/SoftGSM.cpp + create mode 100644 media/libstagefright/codecs/gsm/dec/SoftGSM.h + create mode 100644 media/libstagefright/codecs/gsm/dec/exports.lds + create mode 100644 media/libstagefright/codecs/hevcdec/Android.bp + create mode 100644 media/libstagefright/codecs/hevcdec/SoftHEVC.cpp + create mode 100644 media/libstagefright/codecs/hevcdec/SoftHEVC.h + create mode 100644 media/libstagefright/codecs/hevcdec/exports.lds + create mode 100644 media/libstagefright/codecs/m4v_h263/dec/Android.bp + create mode 100644 media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp + create mode 100644 media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h + create mode 100644 media/libstagefright/codecs/m4v_h263/dec/exports.lds + create mode 100644 media/libstagefright/codecs/m4v_h263/enc/Android.bp + create mode 100644 media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp + create mode 100644 media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h + create mode 100644 media/libstagefright/codecs/m4v_h263/enc/exports.lds + create mode 100644 media/libstagefright/codecs/mp3dec/Android.bp + create mode 100644 media/libstagefright/codecs/mp3dec/SoftMP3.cpp + create mode 100644 media/libstagefright/codecs/mp3dec/SoftMP3.h + create mode 100644 media/libstagefright/codecs/mp3dec/exports.lds + create mode 100644 media/libstagefright/codecs/mpeg2dec/Android.bp + create mode 100644 media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp + create mode 100644 media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h + create mode 100644 media/libstagefright/codecs/mpeg2dec/exports.lds + create mode 100644 media/libstagefright/codecs/on2/dec/Android.bp + create mode 100644 media/libstagefright/codecs/on2/dec/MODULE_LICENSE_APACHE2 + create mode 100644 media/libstagefright/codecs/on2/dec/NOTICE + create mode 100644 media/libstagefright/codecs/on2/dec/SoftVPX.cpp + create mode 100644 media/libstagefright/codecs/on2/dec/SoftVPX.h + create mode 100644 media/libstagefright/codecs/on2/dec/exports.lds + create mode 100644 media/libstagefright/codecs/on2/enc/Android.bp + create mode 100644 media/libstagefright/codecs/on2/enc/MODULE_LICENSE_APACHE2 + create mode 100644 media/libstagefright/codecs/on2/enc/NOTICE + create mode 100644 media/libstagefright/codecs/on2/enc/SoftVP8Encoder.cpp + create mode 100644 media/libstagefright/codecs/on2/enc/SoftVP8Encoder.h + create mode 100644 media/libstagefright/codecs/on2/enc/SoftVP9Encoder.cpp + create mode 100644 media/libstagefright/codecs/on2/enc/SoftVP9Encoder.h + create mode 100644 media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp + create mode 100644 media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h + create mode 100644 media/libstagefright/codecs/on2/enc/exports.lds + create mode 100644 media/libstagefright/codecs/opus/dec/Android.bp + create mode 100644 media/libstagefright/codecs/opus/dec/SoftOpus.cpp + create mode 100644 media/libstagefright/codecs/opus/dec/SoftOpus.h + create mode 100644 media/libstagefright/codecs/opus/dec/exports.lds + create mode 100644 media/libstagefright/codecs/raw/Android.bp + create mode 100644 media/libstagefright/codecs/raw/MODULE_LICENSE_APACHE2 + create mode 100644 media/libstagefright/codecs/raw/NOTICE + create mode 100644 media/libstagefright/codecs/raw/SoftRaw.cpp + create mode 100644 media/libstagefright/codecs/raw/SoftRaw.h + create mode 100644 media/libstagefright/codecs/raw/exports.lds + create mode 100644 media/libstagefright/codecs/vorbis/dec/Android.bp + create mode 100644 media/libstagefright/codecs/vorbis/dec/MODULE_LICENSE_APACHE2 + create mode 100644 media/libstagefright/codecs/vorbis/dec/NOTICE + create mode 100644 media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp + create mode 100644 media/libstagefright/codecs/vorbis/dec/SoftVorbis.h + create mode 100644 media/libstagefright/codecs/vorbis/dec/exports.lds + create mode 100644 media/libstagefright/codecs/xaacdec/Android.bp + create mode 100644 media/libstagefright/codecs/xaacdec/SoftXAAC.cpp + create mode 100644 media/libstagefright/codecs/xaacdec/SoftXAAC.h + +diff --git a/media/libstagefright/codecs/aacdec/Android.bp b/media/libstagefright/codecs/aacdec/Android.bp +new file mode 100644 +index 0000000..5ab49a7 +--- /dev/null ++++ b/media/libstagefright/codecs/aacdec/Android.bp +@@ -0,0 +1,44 @@ ++package { ++ default_applicable_licenses: [ ++ "frameworks_av_media_libstagefright_codecs_aacdec_license", ++ ], ++} ++ ++// Added automatically by a large-scale-change ++// See: http://go/android-license-faq ++license { ++ name: "frameworks_av_media_libstagefright_codecs_aacdec_license", ++ visibility: [":__subpackages__"], ++ license_kinds: [ ++ "SPDX-license-identifier-Apache-2.0", ++ ], ++ license_text: [ ++ "NOTICE", ++ ], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_aacdec", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: [ ++ "SoftAAC2.cpp", ++ "DrcPresModeWrap.cpp", ++ ], ++ ++ version_script: "exports.lds", ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ "unsigned-integer-overflow", ++ ], ++ cfi: true, ++ }, ++ ++ static_libs: ["libFraunhoferAAC"], ++ ++ shared_libs: [ ++ "libcutils", ++ ], ++} +diff --git a/media/libstagefright/codecs/aacdec/DrcPresModeWrap.cpp b/media/libstagefright/codecs/aacdec/DrcPresModeWrap.cpp +new file mode 100644 +index 0000000..157cab6 +--- /dev/null ++++ b/media/libstagefright/codecs/aacdec/DrcPresModeWrap.cpp +@@ -0,0 +1,371 @@ ++/* ++ * Copyright (C) 2014 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. ++ */ ++#include "DrcPresModeWrap.h" ++ ++#include ++ ++#define LOG_TAG "SoftAAC2_DrcWrapper" ++//#define LOG_NDEBUG 0 ++#include ++ ++//#define DRC_PRES_MODE_WRAP_DEBUG ++ ++#define GPM_ENCODER_TARGET_LEVEL 64 ++#define MAX_TARGET_LEVEL 40 ++ ++CDrcPresModeWrapper::CDrcPresModeWrapper() ++{ ++ mDataUpdate = true; ++ ++ /* Data from streamInfo. */ ++ /* Initialized to the same values as in the aac decoder */ ++ mStreamPRL = -1; ++ mStreamDRCPresMode = -1; ++ mStreamNrAACChan = 0; ++ mStreamNrOutChan = 0; ++ ++ /* Desired values (set by user). */ ++ /* Initialized to the same values as in the aac decoder */ ++ mDesTarget = -1; ++ mDesAttFactor = 0; ++ mDesBoostFactor = 0; ++ mDesHeavy = 0; ++ ++ mEncoderTarget = -1; ++ ++ /* Values from last time. */ ++ mLastTarget = -2; ++ mLastAttFactor = -1; ++ mLastBoostFactor = -1; ++ mLastHeavy = 0; ++} ++ ++CDrcPresModeWrapper::~CDrcPresModeWrapper() ++{ ++} ++ ++void ++CDrcPresModeWrapper::setDecoderHandle(const HANDLE_AACDECODER handle) ++{ ++ mHandleDecoder = handle; ++} ++ ++void ++CDrcPresModeWrapper::submitStreamData(CStreamInfo* pStreamInfo) ++{ ++ assert(pStreamInfo); ++ ++ if (mStreamPRL != pStreamInfo->drcProgRefLev) { ++ mStreamPRL = pStreamInfo->drcProgRefLev; ++ mDataUpdate = true; ++#ifdef DRC_PRES_MODE_WRAP_DEBUG ++ ALOGV("DRC presentation mode wrapper: drcProgRefLev is %d\n", mStreamPRL); ++#endif ++ } ++ ++ if (mStreamDRCPresMode != pStreamInfo->drcPresMode) { ++ mStreamDRCPresMode = pStreamInfo->drcPresMode; ++ mDataUpdate = true; ++#ifdef DRC_PRES_MODE_WRAP_DEBUG ++ ALOGV("DRC presentation mode wrapper: drcPresMode is %d\n", mStreamDRCPresMode); ++#endif ++ } ++ ++ if (mStreamNrAACChan != pStreamInfo->aacNumChannels) { ++ mStreamNrAACChan = pStreamInfo->aacNumChannels; ++ mDataUpdate = true; ++#ifdef DRC_PRES_MODE_WRAP_DEBUG ++ ALOGV("DRC presentation mode wrapper: aacNumChannels is %d\n", mStreamNrAACChan); ++#endif ++ } ++ ++ if (mStreamNrOutChan != pStreamInfo->numChannels) { ++ mStreamNrOutChan = pStreamInfo->numChannels; ++ mDataUpdate = true; ++#ifdef DRC_PRES_MODE_WRAP_DEBUG ++ ALOGV("DRC presentation mode wrapper: numChannels is %d\n", mStreamNrOutChan); ++#endif ++ } ++ ++ ++ ++ if (mStreamNrOutChan -31 dB ++ if ((mIsStereoDownmix == false) && (mIsMonoDownmix == false)) { ++ // no stereo or mono downmixing, calculated scaling of light DRC ++ /* use as little compression as possible */ ++ newAttFactor = 0; ++ newBoostFactor = 0; ++ if (mDesTarget PRL ++ if (mEncoderTarget < mDesTarget) { // if mEncoderTarget > target level ++ // mEncoderTarget > target level > PRL ++ int calcFactor; ++ float calcFactor_norm; ++ // 0.0f < calcFactor_norm < 1.0f ++ calcFactor_norm = (float)(mDesTarget - progRefLevel) / ++ (float)(mEncoderTarget - progRefLevel); ++ calcFactor = (int)(calcFactor_norm*127.0f); // 0 <= calcFactor < 127 ++ // calcFactor is the lower limit ++ newAttFactor = (calcFactor>newAttFactor) ? calcFactor : newAttFactor; ++ // new AttFactor will be always = calcFactor, as it is set to 0 before. ++ newBoostFactor = newAttFactor; ++ } else { ++ /* target level > mEncoderTarget > PRL */ ++ // newTDLimiterEnable = 1; ++ // the time domain limiter must always be active in this case. ++ // It is assumed that the framework activates it by default ++ newAttFactor = 127; ++ newBoostFactor = 127; ++ } ++ } else { // target level <= PRL ++ // no restrictions required ++ // newAttFactor = newAttFactor; ++ } ++ } else { // downmixing ++ // if target level > -23 dB or mono downmix ++ if ( (mDesTarget<92) || mIsMonoDownmix ) { ++ newHeavy = 1; ++ } else { ++ // we perform a downmix, so, we need at least full light DRC ++ newAttFactor = 127; ++ } ++ } ++ } else { // target level <= -31 dB ++ // playback -31 dB: light DRC only needed if we perform downmixing ++ if (mIsDownmix) { // we do downmixing ++ newAttFactor = 127; ++ } ++ } ++ } ++ else { // handle other used encoder target levels ++ ++ // Validation check: DRC presentation mode is only specified for max. 5.1 channels ++ if (mStreamNrAACChan > 6) { ++ drcPresMode = 0; ++ } ++ ++ switch (drcPresMode) { ++ case 0: ++ default: // presentation mode not indicated ++ { ++ ++ if (mDesTarget<124) { // if target level > -31 dB ++ // no stereo or mono downmixing ++ if ((mIsStereoDownmix == false) && (mIsMonoDownmix == false)) { ++ if (mDesTarget PRL ++ // newTDLimiterEnable = 1; ++ // the time domain limiter must always be active in this case. ++ // It is assumed that the framework activates it by default ++ newAttFactor = 127; // at least, use light compression ++ } else { // target level <= PRL ++ // no restrictions required ++ // newAttFactor = newAttFactor; ++ } ++ } else { // downmixing ++ // newTDLimiterEnable = 1; ++ // the time domain limiter must always be active in this case. ++ // It is assumed that the framework activates it by default ++ ++ // if target level > -23 dB or mono downmix ++ if ( (mDesTarget < 92) || mIsMonoDownmix ) { ++ newHeavy = 1; ++ } else{ ++ // we perform a downmix, so, we need at least full light DRC ++ newAttFactor = 127; ++ } ++ } ++ } else { // target level <= -31 dB ++ if (mIsDownmix) { // we do downmixing. ++ // newTDLimiterEnable = 1; ++ // the time domain limiter must always be active in this case. ++ // It is assumed that the framework activates it by default ++ newAttFactor = 127; ++ } ++ } ++ } ++ break; ++ ++ // Presentation mode 1 and 2 according to ETSI TS 101 154: ++ // Digital Video Broadcasting (DVB); Specification for the use of Video and Audio Coding ++ // in Broadcasting Applications based on the MPEG-2 Transport Stream, ++ // section C.5.4., "Decoding", and Table C.33 ++ // ISO DRC -> newHeavy = 0 (Use light compression, MPEG-style) ++ // Compression_value -> newHeavy = 1 (Use heavy compression, DVB-style) ++ // scaling restricted -> newAttFactor = 127 ++ ++ case 1: // presentation mode 1, Light:-31/Heavy:-23 ++ { ++ if (mDesTarget < 124) { // if target level > -31 dB ++ // playback up to -23 dB ++ newHeavy = 1; ++ } else { // target level <= -31 dB ++ // playback -31 dB ++ if (mIsDownmix) { // we do downmixing. ++ newAttFactor = 127; ++ } ++ } ++ } ++ break; ++ ++ case 2: // presentation mode 2, Light:-23/Heavy:-23 ++ { ++ if (mDesTarget < 124) { // if target level > -31 dB ++ // playback up to -23 dB ++ if (mIsMonoDownmix) { // if mono downmix ++ newHeavy = 1; ++ } else { ++ newHeavy = 0; ++ newAttFactor = 127; ++ } ++ } else { // target level <= -31 dB ++ // playback -31 dB ++ newHeavy = 0; ++ if (mIsDownmix) { // we do downmixing. ++ newAttFactor = 127; ++ } ++ } ++ } ++ break; ++ ++ } // switch() ++ } // if (mEncoderTarget == GPM_ENCODER_TARGET_LEVEL) ++ ++ // validation check again ++ if (newHeavy == 1) { ++ newBoostFactor=127; // not really needed as the same would be done by the decoder anyway ++ newAttFactor = 127; ++ } ++ ++ // update the decoder ++ if (newTarget != mLastTarget) { ++ aacDecoder_SetParam(mHandleDecoder, AAC_DRC_REFERENCE_LEVEL, newTarget); ++ mLastTarget = newTarget; ++#ifdef DRC_PRES_MODE_WRAP_DEBUG ++ if (newTarget != mDesTarget) ++ ALOGV("DRC presentation mode wrapper: forced target level to %d (from %d)\n", newTarget, mDesTarget); ++ else ++ ALOGV("DRC presentation mode wrapper: set target level to %d\n", newTarget); ++#endif ++ } ++ ++ if (newAttFactor != mLastAttFactor) { ++ aacDecoder_SetParam(mHandleDecoder, AAC_DRC_ATTENUATION_FACTOR, newAttFactor); ++ mLastAttFactor = newAttFactor; ++#ifdef DRC_PRES_MODE_WRAP_DEBUG ++ if (newAttFactor != mDesAttFactor) ++ ALOGV("DRC presentation mode wrapper: forced attenuation factor to %d (from %d)\n", newAttFactor, mDesAttFactor); ++ else ++ ALOGV("DRC presentation mode wrapper: set attenuation factor to %d\n", newAttFactor); ++#endif ++ } ++ ++ if (newBoostFactor != mLastBoostFactor) { ++ aacDecoder_SetParam(mHandleDecoder, AAC_DRC_BOOST_FACTOR, newBoostFactor); ++ mLastBoostFactor = newBoostFactor; ++#ifdef DRC_PRES_MODE_WRAP_DEBUG ++ if (newBoostFactor != mDesBoostFactor) ++ ALOGV("DRC presentation mode wrapper: forced boost factor to %d (from %d)\n", ++ newBoostFactor, mDesBoostFactor); ++ else ++ ALOGV("DRC presentation mode wrapper: set boost factor to %d\n", newBoostFactor); ++#endif ++ } ++ ++ if (newHeavy != mLastHeavy) { ++ aacDecoder_SetParam(mHandleDecoder, AAC_DRC_HEAVY_COMPRESSION, newHeavy); ++ mLastHeavy = newHeavy; ++#ifdef DRC_PRES_MODE_WRAP_DEBUG ++ if (newHeavy != mDesHeavy) ++ ALOGV("DRC presentation mode wrapper: forced heavy compression to %d (from %d)\n", ++ newHeavy, mDesHeavy); ++ else ++ ALOGV("DRC presentation mode wrapper: set heavy compression to %d\n", newHeavy); ++#endif ++ } ++ ++#ifdef DRC_PRES_MODE_WRAP_DEBUG ++ ALOGV("DRC config: tgt_lev: %3d, cut: %3d, boost: %3d, heavy: %d\n", newTarget, ++ newAttFactor, newBoostFactor, newHeavy); ++#endif ++ mDataUpdate = false; ++ ++ } // if (mDataUpdate) ++} +diff --git a/media/libstagefright/codecs/aacdec/DrcPresModeWrap.h b/media/libstagefright/codecs/aacdec/DrcPresModeWrap.h +new file mode 100644 +index 0000000..f0b6cf2 +--- /dev/null ++++ b/media/libstagefright/codecs/aacdec/DrcPresModeWrap.h +@@ -0,0 +1,62 @@ ++/* ++ * Copyright (C) 2014 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 "aacdecoder_lib.h" ++ ++typedef enum ++{ ++ DRC_PRES_MODE_WRAP_DESIRED_TARGET = 0x0000, ++ DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR = 0x0001, ++ DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR = 0x0002, ++ DRC_PRES_MODE_WRAP_DESIRED_HEAVY = 0x0003, ++ DRC_PRES_MODE_WRAP_ENCODER_TARGET = 0x0004 ++} DRC_PRES_MODE_WRAP_PARAM; ++ ++ ++class CDrcPresModeWrapper { ++public: ++ CDrcPresModeWrapper(); ++ ~CDrcPresModeWrapper(); ++ void setDecoderHandle(const HANDLE_AACDECODER handle); ++ void setParam(const DRC_PRES_MODE_WRAP_PARAM param, const int value); ++ void submitStreamData(CStreamInfo*); ++ void update(); ++ ++protected: ++ HANDLE_AACDECODER mHandleDecoder; ++ int mDesTarget; ++ int mDesAttFactor; ++ int mDesBoostFactor; ++ int mDesHeavy; ++ ++ int mEncoderTarget; ++ ++ int mLastTarget; ++ int mLastAttFactor; ++ int mLastBoostFactor; ++ int mLastHeavy; ++ ++ SCHAR mStreamPRL; ++ SCHAR mStreamDRCPresMode; ++ INT mStreamNrAACChan; ++ INT mStreamNrOutChan; ++ ++ bool mIsDownmix; ++ bool mIsMonoDownmix; ++ bool mIsStereoDownmix; ++ ++ bool mDataUpdate; ++}; +diff --git a/media/libstagefright/codecs/aacdec/MODULE_LICENSE_APACHE2 b/media/libstagefright/codecs/aacdec/MODULE_LICENSE_APACHE2 +new file mode 100644 +index 0000000..e69de29 +diff --git a/media/libstagefright/codecs/aacdec/NOTICE b/media/libstagefright/codecs/aacdec/NOTICE +new file mode 100644 +index 0000000..c5b1efa +--- /dev/null ++++ b/media/libstagefright/codecs/aacdec/NOTICE +@@ -0,0 +1,190 @@ ++ ++ Copyright (c) 2005-2008, 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. ++ ++ 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. ++ ++ ++ Apache License ++ Version 2.0, January 2004 ++ http://www.apache.org/licenses/ ++ ++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION ++ ++ 1. Definitions. ++ ++ "License" shall mean the terms and conditions for use, reproduction, ++ and distribution as defined by Sections 1 through 9 of this document. ++ ++ "Licensor" shall mean the copyright owner or entity authorized by ++ the copyright owner that is granting the License. ++ ++ "Legal Entity" shall mean the union of the acting entity and all ++ other entities that control, are controlled by, or are under common ++ control with that entity. For the purposes of this definition, ++ "control" means (i) the power, direct or indirect, to cause the ++ direction or management of such entity, whether by contract or ++ otherwise, or (ii) ownership of fifty percent (50%) or more of the ++ outstanding shares, or (iii) beneficial ownership of such entity. ++ ++ "You" (or "Your") shall mean an individual or Legal Entity ++ exercising permissions granted by this License. ++ ++ "Source" form shall mean the preferred form for making modifications, ++ including but not limited to software source code, documentation ++ source, and configuration files. ++ ++ "Object" form shall mean any form resulting from mechanical ++ transformation or translation of a Source form, including but ++ not limited to compiled object code, generated documentation, ++ and conversions to other media types. ++ ++ "Work" shall mean the work of authorship, whether in Source or ++ Object form, made available under the License, as indicated by a ++ copyright notice that is included in or attached to the work ++ (an example is provided in the Appendix below). ++ ++ "Derivative Works" shall mean any work, whether in Source or Object ++ form, that is based on (or derived from) the Work and for which the ++ editorial revisions, annotations, elaborations, or other modifications ++ represent, as a whole, an original work of authorship. For the purposes ++ of this License, Derivative Works shall not include works that remain ++ separable from, or merely link (or bind by name) to the interfaces of, ++ the Work and Derivative Works thereof. ++ ++ "Contribution" shall mean any work of authorship, including ++ the original version of the Work and any modifications or additions ++ to that Work or Derivative Works thereof, that is intentionally ++ submitted to Licensor for inclusion in the Work by the copyright owner ++ or by an individual or Legal Entity authorized to submit on behalf of ++ the copyright owner. For the purposes of this definition, "submitted" ++ means any form of electronic, verbal, or written communication sent ++ to the Licensor or its representatives, including but not limited to ++ communication on electronic mailing lists, source code control systems, ++ and issue tracking systems that are managed by, or on behalf of, the ++ Licensor for the purpose of discussing and improving the Work, but ++ excluding communication that is conspicuously marked or otherwise ++ designated in writing by the copyright owner as "Not a Contribution." ++ ++ "Contributor" shall mean Licensor and any individual or Legal Entity ++ on behalf of whom a Contribution has been received by Licensor and ++ subsequently incorporated within the Work. ++ ++ 2. Grant of Copyright License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ copyright license to reproduce, prepare Derivative Works of, ++ publicly display, publicly perform, sublicense, and distribute the ++ Work and such Derivative Works in Source or Object form. ++ ++ 3. Grant of Patent License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ (except as stated in this section) patent license to make, have made, ++ use, offer to sell, sell, import, and otherwise transfer the Work, ++ where such license applies only to those patent claims licensable ++ by such Contributor that are necessarily infringed by their ++ Contribution(s) alone or by combination of their Contribution(s) ++ with the Work to which such Contribution(s) was submitted. If You ++ institute patent litigation against any entity (including a ++ cross-claim or counterclaim in a lawsuit) alleging that the Work ++ or a Contribution incorporated within the Work constitutes direct ++ or contributory patent infringement, then any patent licenses ++ granted to You under this License for that Work shall terminate ++ as of the date such litigation is filed. ++ ++ 4. Redistribution. You may reproduce and distribute copies of the ++ Work or Derivative Works thereof in any medium, with or without ++ modifications, and in Source or Object form, provided that You ++ meet the following conditions: ++ ++ (a) You must give any other recipients of the Work or ++ Derivative Works a copy of this License; and ++ ++ (b) You must cause any modified files to carry prominent notices ++ stating that You changed the files; and ++ ++ (c) You must retain, in the Source form of any Derivative Works ++ that You distribute, all copyright, patent, trademark, and ++ attribution notices from the Source form of the Work, ++ excluding those notices that do not pertain to any part of ++ the Derivative Works; and ++ ++ (d) If the Work includes a "NOTICE" text file as part of its ++ distribution, then any Derivative Works that You distribute must ++ include a readable copy of the attribution notices contained ++ within such NOTICE file, excluding those notices that do not ++ pertain to any part of the Derivative Works, in at least one ++ of the following places: within a NOTICE text file distributed ++ as part of the Derivative Works; within the Source form or ++ documentation, if provided along with the Derivative Works; or, ++ within a display generated by the Derivative Works, if and ++ wherever such third-party notices normally appear. The contents ++ of the NOTICE file are for informational purposes only and ++ do not modify the License. You may add Your own attribution ++ notices within Derivative Works that You distribute, alongside ++ or as an addendum to the NOTICE text from the Work, provided ++ that such additional attribution notices cannot be construed ++ as modifying the License. ++ ++ You may add Your own copyright statement to Your modifications and ++ may provide additional or different license terms and conditions ++ for use, reproduction, or distribution of Your modifications, or ++ for any such Derivative Works as a whole, provided Your use, ++ reproduction, and distribution of the Work otherwise complies with ++ the conditions stated in this License. ++ ++ 5. Submission of Contributions. Unless You explicitly state otherwise, ++ any Contribution intentionally submitted for inclusion in the Work ++ by You to the Licensor shall be under the terms and conditions of ++ this License, without any additional terms or conditions. ++ Notwithstanding the above, nothing herein shall supersede or modify ++ the terms of any separate license agreement you may have executed ++ with Licensor regarding such Contributions. ++ ++ 6. Trademarks. This License does not grant permission to use the trade ++ names, trademarks, service marks, or product names of the Licensor, ++ except as required for reasonable and customary use in describing the ++ origin of the Work and reproducing the content of the NOTICE file. ++ ++ 7. Disclaimer of Warranty. Unless required by applicable law or ++ agreed to in writing, Licensor provides the Work (and each ++ Contributor provides its Contributions) on an "AS IS" BASIS, ++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or ++ implied, including, without limitation, any warranties or conditions ++ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A ++ PARTICULAR PURPOSE. You are solely responsible for determining the ++ appropriateness of using or redistributing the Work and assume any ++ risks associated with Your exercise of permissions under this License. ++ ++ 8. Limitation of Liability. In no event and under no legal theory, ++ whether in tort (including negligence), contract, or otherwise, ++ unless required by applicable law (such as deliberate and grossly ++ negligent acts) or agreed to in writing, shall any Contributor be ++ liable to You for damages, including any direct, indirect, special, ++ incidental, or consequential damages of any character arising as a ++ result of this License or out of the use or inability to use the ++ Work (including but not limited to damages for loss of goodwill, ++ work stoppage, computer failure or malfunction, or any and all ++ other commercial damages or losses), even if such Contributor ++ has been advised of the possibility of such damages. ++ ++ 9. Accepting Warranty or Additional Liability. While redistributing ++ the Work or Derivative Works thereof, You may choose to offer, ++ and charge a fee for, acceptance of support, warranty, indemnity, ++ or other liability obligations and/or rights consistent with this ++ License. However, in accepting such obligations, You may act only ++ on Your own behalf and on Your sole responsibility, not on behalf ++ of any other Contributor, and only if You agree to indemnify, ++ defend, and hold each Contributor harmless for any liability ++ incurred by, or claims asserted against, such Contributor by reason ++ of your accepting any such warranty or additional liability. ++ ++ END OF TERMS AND CONDITIONS ++ +diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +new file mode 100644 +index 0000000..92ec94f +--- /dev/null ++++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +@@ -0,0 +1,1255 @@ ++/* ++ * Copyright (C) 2012 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 "SoftAAC2" ++#include ++ ++#include "SoftAAC2.h" ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define FILEREAD_MAX_LAYERS 2 ++ ++#define DRC_DEFAULT_MOBILE_REF_LEVEL 64 /* 64*-0.25dB = -16 dB below full scale for mobile conf */ ++#define DRC_DEFAULT_MOBILE_DRC_CUT 127 /* maximum compression of dynamic range for mobile conf */ ++#define DRC_DEFAULT_MOBILE_DRC_BOOST 127 /* maximum compression of dynamic range for mobile conf */ ++#define DRC_DEFAULT_MOBILE_DRC_HEAVY 1 /* switch for heavy compression for mobile conf */ ++#define DRC_DEFAULT_MOBILE_DRC_EFFECT 3 /* MPEG-D DRC effect type; 3 => Limited playback range */ ++#define DRC_DEFAULT_MOBILE_DRC_ALBUM 0 /* MPEG-D DRC album mode; 0 => album mode is disabled, 1 => album mode is enabled */ ++#define DRC_DEFAULT_MOBILE_OUTPUT_LOUDNESS -1 /* decoder output loudness; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */ ++#define DRC_DEFAULT_MOBILE_ENC_LEVEL (-1) /* encoder target level; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */ ++#define MAX_CHANNEL_COUNT 8 /* maximum number of audio channels that can be decoded */ ++// names of properties that can be used to override the default DRC settings ++#define PROP_DRC_OVERRIDE_REF_LEVEL "aac_drc_reference_level" ++#define PROP_DRC_OVERRIDE_CUT "aac_drc_cut" ++#define PROP_DRC_OVERRIDE_BOOST "aac_drc_boost" ++#define PROP_DRC_OVERRIDE_HEAVY "aac_drc_heavy" ++#define PROP_DRC_OVERRIDE_ENC_LEVEL "aac_drc_enc_target_level" ++#define PROP_DRC_OVERRIDE_EFFECT "ro.aac_drc_effect_type" ++ ++namespace android { ++ ++template ++static void InitOMXParams(T *params) { ++ params->nSize = sizeof(T); ++ params->nVersion.s.nVersionMajor = 1; ++ params->nVersion.s.nVersionMinor = 0; ++ params->nVersion.s.nRevision = 0; ++ params->nVersion.s.nStep = 0; ++} ++ ++static const OMX_U32 kSupportedProfiles[] = { ++ OMX_AUDIO_AACObjectLC, ++ OMX_AUDIO_AACObjectHE, ++ OMX_AUDIO_AACObjectHE_PS, ++ OMX_AUDIO_AACObjectLD, ++ OMX_AUDIO_AACObjectELD, ++ OMX_AUDIO_AACObjectER_Scalable, ++ OMX_AUDIO_AACObjectXHE, ++}; ++ ++SoftAAC2::SoftAAC2( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SimpleSoftOMXComponent(name, callbacks, appData, component), ++ mAACDecoder(NULL), ++ mStreamInfo(NULL), ++ mIsADTS(false), ++ mInputBufferCount(0), ++ mOutputBufferCount(0), ++ mSignalledError(false), ++ mLastInHeader(NULL), ++ mOutputPortSettingsChange(NONE) { ++ initPorts(); ++ CHECK_EQ(initDecoder(), (status_t)OK); ++} ++ ++SoftAAC2::~SoftAAC2() { ++ aacDecoder_Close(mAACDecoder); ++ delete[] mOutputDelayRingBuffer; ++} ++ ++void SoftAAC2::initPorts() { ++ OMX_PARAM_PORTDEFINITIONTYPE def; ++ InitOMXParams(&def); ++ ++ def.nPortIndex = 0; ++ def.eDir = OMX_DirInput; ++ def.nBufferCountMin = kNumInputBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = 8192; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 1; ++ ++ def.format.audio.cMIMEType = const_cast("audio/aac"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingAAC; ++ ++ addPort(def); ++ ++ def.nPortIndex = 1; ++ def.eDir = OMX_DirOutput; ++ def.nBufferCountMin = kNumOutputBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = 4096 * MAX_CHANNEL_COUNT; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 2; ++ ++ def.format.audio.cMIMEType = const_cast("audio/raw"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; ++ ++ addPort(def); ++} ++ ++status_t SoftAAC2::initDecoder() { ++ ALOGV("initDecoder()"); ++ status_t status = UNKNOWN_ERROR; ++ mAACDecoder = aacDecoder_Open(TT_MP4_ADIF, /* num layers */ 1); ++ if (mAACDecoder != NULL) { ++ mStreamInfo = aacDecoder_GetStreamInfo(mAACDecoder); ++ if (mStreamInfo != NULL) { ++ status = OK; ++ } ++ } ++ ++ mEndOfInput = false; ++ mEndOfOutput = false; ++ mOutputDelayCompensated = 0; ++ mOutputDelayRingBufferSize = 2048 * MAX_CHANNEL_COUNT * kNumDelayBlocksMax; ++ mOutputDelayRingBuffer = new int16_t[mOutputDelayRingBufferSize]; ++ mOutputDelayRingBufferWritePos = 0; ++ mOutputDelayRingBufferReadPos = 0; ++ mOutputDelayRingBufferFilled = 0; ++ ++ if (mAACDecoder == NULL) { ++ ALOGE("AAC decoder is null. TODO: Can not call aacDecoder_SetParam in the following code"); ++ } ++ ++ //aacDecoder_SetParam(mAACDecoder, AAC_PCM_LIMITER_ENABLE, 0); ++ ++ //init DRC wrapper ++ mDrcWrap.setDecoderHandle(mAACDecoder); ++ mDrcWrap.submitStreamData(mStreamInfo); ++ ++ // for streams that contain metadata, use the mobile profile DRC settings unless overridden by platform properties ++ // TODO: change the DRC settings depending on audio output device type (HDMI, loadspeaker, headphone) ++ char value[PROPERTY_VALUE_MAX]; ++ // DRC_PRES_MODE_WRAP_DESIRED_TARGET ++ if (property_get(PROP_DRC_OVERRIDE_REF_LEVEL, value, NULL)) { ++ unsigned refLevel = atoi(value); ++ ALOGV("AAC decoder using desired DRC target reference level of %d instead of %d", refLevel, ++ DRC_DEFAULT_MOBILE_REF_LEVEL); ++ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_TARGET, refLevel); ++ } else { ++ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_TARGET, DRC_DEFAULT_MOBILE_REF_LEVEL); ++ } ++ // DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR ++ if (property_get(PROP_DRC_OVERRIDE_CUT, value, NULL)) { ++ unsigned cut = atoi(value); ++ ALOGV("AAC decoder using desired DRC attenuation factor of %d instead of %d", cut, ++ DRC_DEFAULT_MOBILE_DRC_CUT); ++ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR, cut); ++ } else { ++ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR, DRC_DEFAULT_MOBILE_DRC_CUT); ++ } ++ // DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR ++ if (property_get(PROP_DRC_OVERRIDE_BOOST, value, NULL)) { ++ unsigned boost = atoi(value); ++ ALOGV("AAC decoder using desired DRC boost factor of %d instead of %d", boost, ++ DRC_DEFAULT_MOBILE_DRC_BOOST); ++ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR, boost); ++ } else { ++ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR, DRC_DEFAULT_MOBILE_DRC_BOOST); ++ } ++ // DRC_PRES_MODE_WRAP_DESIRED_HEAVY ++ if (property_get(PROP_DRC_OVERRIDE_HEAVY, value, NULL)) { ++ unsigned heavy = atoi(value); ++ ALOGV("AAC decoder using desried DRC heavy compression switch of %d instead of %d", heavy, ++ DRC_DEFAULT_MOBILE_DRC_HEAVY); ++ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_HEAVY, heavy); ++ } else { ++ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_HEAVY, DRC_DEFAULT_MOBILE_DRC_HEAVY); ++ } ++ // DRC_PRES_MODE_WRAP_ENCODER_TARGET ++ if (property_get(PROP_DRC_OVERRIDE_ENC_LEVEL, value, NULL)) { ++ unsigned encoderRefLevel = atoi(value); ++ ALOGV("AAC decoder using encoder-side DRC reference level of %d instead of %d", ++ encoderRefLevel, DRC_DEFAULT_MOBILE_ENC_LEVEL); ++ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_ENCODER_TARGET, encoderRefLevel); ++ } else { ++ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_ENCODER_TARGET, DRC_DEFAULT_MOBILE_ENC_LEVEL); ++ } ++ // AAC_UNIDRC_SET_EFFECT ++ int32_t effectType = ++ property_get_int32(PROP_DRC_OVERRIDE_EFFECT, DRC_DEFAULT_MOBILE_DRC_EFFECT); ++ if (effectType < -1 || effectType > 8) { ++ effectType = DRC_DEFAULT_MOBILE_DRC_EFFECT; ++ } ++ ALOGV("AAC decoder using MPEG-D DRC effect type %d (default=%d)", ++ effectType, DRC_DEFAULT_MOBILE_DRC_EFFECT); ++ aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_SET_EFFECT, effectType); ++ // AAC_UNIDRC_ALBUM_MODE ++ int32_t albumMode = DRC_DEFAULT_MOBILE_DRC_ALBUM; ++ ALOGV("AAC decoder using MPEG-D Album mode value %d (default=%d)", albumMode, ++ DRC_DEFAULT_MOBILE_DRC_ALBUM); ++ aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_ALBUM_MODE, albumMode); ++ ++ // By default, the decoder creates a 5.1 channel downmix signal. ++ // For seven and eight channel input streams, enable 6.1 and 7.1 channel output ++ aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, -1); ++ ++ mDrcCompressMode = DRC_DEFAULT_MOBILE_DRC_HEAVY; ++ mDrcTargetRefLevel = DRC_DEFAULT_MOBILE_REF_LEVEL; ++ mDrcEncTargetLevel = DRC_DEFAULT_MOBILE_ENC_LEVEL; ++ mDrcBoostFactor = DRC_DEFAULT_MOBILE_DRC_BOOST; ++ mDrcAttenuationFactor = DRC_DEFAULT_MOBILE_DRC_CUT; ++ mDrcEffectType = DRC_DEFAULT_MOBILE_DRC_EFFECT; ++ mDrcAlbumMode = DRC_DEFAULT_MOBILE_DRC_ALBUM; ++ mDrcOutputLoudness = DRC_DEFAULT_MOBILE_OUTPUT_LOUDNESS; ++ ++ return status; ++} ++ ++OMX_ERRORTYPE SoftAAC2::internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params) { ++ switch ((OMX_U32) index) { ++ case OMX_IndexParamAudioPortFormat: ++ { ++ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (formatParams->nIndex > 0) { ++ return OMX_ErrorNoMore; ++ } ++ ++ formatParams->eEncoding = ++ (formatParams->nPortIndex == 0) ++ ? OMX_AUDIO_CodingAAC : OMX_AUDIO_CodingPCM; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioAac: ++ { ++ OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = ++ (OMX_AUDIO_PARAM_AACPROFILETYPE *)params; ++ ++ if (!isValidOMXParam(aacParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (aacParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ aacParams->nBitRate = 0; ++ aacParams->nAudioBandWidth = 0; ++ aacParams->nAACtools = 0; ++ aacParams->nAACERtools = 0; ++ aacParams->eAACProfile = OMX_AUDIO_AACObjectMain; ++ ++ aacParams->eAACStreamFormat = ++ mIsADTS ++ ? OMX_AUDIO_AACStreamFormatMP4ADTS ++ : OMX_AUDIO_AACStreamFormatMP4FF; ++ ++ aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo; ++ ++ if (!isConfigured()) { ++ aacParams->nChannels = 1; ++ aacParams->nSampleRate = 44100; ++ aacParams->nFrameLength = 0; ++ } else { ++ aacParams->nChannels = mStreamInfo->numChannels; ++ aacParams->nSampleRate = mStreamInfo->sampleRate; ++ aacParams->nFrameLength = mStreamInfo->frameSize; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ pcmParams->eNumData = OMX_NumericalDataSigned; ++ pcmParams->eEndian = OMX_EndianBig; ++ pcmParams->bInterleaved = OMX_TRUE; ++ pcmParams->nBitPerSample = 16; ++ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; ++ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; ++ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; ++ pcmParams->eChannelMapping[2] = OMX_AUDIO_ChannelCF; ++ pcmParams->eChannelMapping[3] = OMX_AUDIO_ChannelLFE; ++ pcmParams->eChannelMapping[4] = OMX_AUDIO_ChannelLS; ++ pcmParams->eChannelMapping[5] = OMX_AUDIO_ChannelRS; ++ ++ if (!isConfigured()) { ++ pcmParams->nChannels = 1; ++ pcmParams->nSamplingRate = 44100; ++ } else { ++ pcmParams->nChannels = mStreamInfo->numChannels; ++ pcmParams->nSamplingRate = mStreamInfo->sampleRate; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioProfileQuerySupported: ++ { ++ OMX_AUDIO_PARAM_ANDROID_PROFILETYPE *profileParams = ++ (OMX_AUDIO_PARAM_ANDROID_PROFILETYPE *)params; ++ ++ if (!isValidOMXParam(profileParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (profileParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (profileParams->nProfileIndex >= NELEM(kSupportedProfiles)) { ++ return OMX_ErrorNoMore; ++ } ++ ++ profileParams->eProfile = ++ kSupportedProfiles[profileParams->nProfileIndex]; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioAndroidAacDrcPresentation: ++ { ++ OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE *aacPresParams = ++ (OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE *)params; ++ ++ ALOGD("get OMX_IndexParamAudioAndroidAacDrcPresentation"); ++ ++ if (!isValidOMXParam(aacPresParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ aacPresParams->nDrcEffectType = mDrcEffectType; ++ aacPresParams->nDrcAlbumMode = mDrcAlbumMode; ++ aacPresParams->nDrcBoost = mDrcBoostFactor; ++ aacPresParams->nDrcCut = mDrcAttenuationFactor; ++ aacPresParams->nHeavyCompression = mDrcCompressMode; ++ aacPresParams->nTargetReferenceLevel = mDrcTargetRefLevel; ++ aacPresParams->nEncodedTargetLevel = mDrcEncTargetLevel; ++ aacPresParams ->nDrcOutputLoudness = mDrcOutputLoudness; ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalGetParameter(index, params); ++ } ++} ++ ++OMX_ERRORTYPE SoftAAC2::internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params) { ++ switch ((int)index) { ++ case OMX_IndexParamStandardComponentRole: ++ { ++ const OMX_PARAM_COMPONENTROLETYPE *roleParams = ++ (const OMX_PARAM_COMPONENTROLETYPE *)params; ++ ++ if (!isValidOMXParam(roleParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (strncmp((const char *)roleParams->cRole, ++ "audio_decoder.aac", ++ OMX_MAX_STRINGNAME_SIZE - 1)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPortFormat: ++ { ++ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if ((formatParams->nPortIndex == 0 ++ && formatParams->eEncoding != OMX_AUDIO_CodingAAC) ++ || (formatParams->nPortIndex == 1 ++ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioAac: ++ { ++ const OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = ++ (const OMX_AUDIO_PARAM_AACPROFILETYPE *)params; ++ ++ if (!isValidOMXParam(aacParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (aacParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (aacParams->eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4FF) { ++ mIsADTS = false; ++ } else if (aacParams->eAACStreamFormat ++ == OMX_AUDIO_AACStreamFormatMP4ADTS) { ++ mIsADTS = true; ++ } else { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioAndroidAacDrcPresentation: ++ { ++ const OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE *aacPresParams = ++ (const OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE *)params; ++ ++ if (!isValidOMXParam(aacPresParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ // for the following parameters of the OMX_AUDIO_PARAM_AACPROFILETYPE structure, ++ // a value of -1 implies the parameter is not set by the application: ++ // nMaxOutputChannels -1 by default ++ // nDrcCut uses default platform properties, see initDecoder() ++ // nDrcBoost idem ++ // nHeavyCompression idem ++ // nTargetReferenceLevel idem ++ // nEncodedTargetLevel idem ++ if (aacPresParams->nMaxOutputChannels >= 0) { ++ int max; ++ if (aacPresParams->nMaxOutputChannels >= 8) { max = 8; } ++ else if (aacPresParams->nMaxOutputChannels >= 6) { max = 6; } ++ else if (aacPresParams->nMaxOutputChannels >= 2) { max = 2; } ++ else { ++ // -1 or 0: disable downmix, 1: mono ++ max = aacPresParams->nMaxOutputChannels; ++ } ++ ALOGV("set nMaxOutputChannels=%d", max); ++ aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, max); ++ } ++ if (aacPresParams->nDrcEffectType >= -1) { ++ ALOGV("set nDrcEffectType=%d", aacPresParams->nDrcEffectType); ++ aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_SET_EFFECT, aacPresParams->nDrcEffectType); ++ mDrcEffectType = aacPresParams->nDrcEffectType; ++ } ++ if (aacPresParams->nDrcAlbumMode >= -1) { ++ ALOGV("set nDrcAlbumMode=%d", aacPresParams->nDrcAlbumMode); ++ aacDecoder_SetParam(mAACDecoder, AAC_UNIDRC_ALBUM_MODE, ++ aacPresParams->nDrcAlbumMode); ++ mDrcAlbumMode = aacPresParams->nDrcAlbumMode; ++ } ++ bool updateDrcWrapper = false; ++ if (aacPresParams->nDrcBoost >= 0) { ++ ALOGV("set nDrcBoost=%d", aacPresParams->nDrcBoost); ++ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR, ++ aacPresParams->nDrcBoost); ++ updateDrcWrapper = true; ++ mDrcBoostFactor = aacPresParams->nDrcBoost; ++ } ++ if (aacPresParams->nDrcCut >= 0) { ++ ALOGV("set nDrcCut=%d", aacPresParams->nDrcCut); ++ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR, aacPresParams->nDrcCut); ++ updateDrcWrapper = true; ++ mDrcAttenuationFactor = aacPresParams->nDrcCut; ++ } ++ if (aacPresParams->nHeavyCompression >= 0) { ++ ALOGV("set nHeavyCompression=%d", aacPresParams->nHeavyCompression); ++ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_HEAVY, ++ aacPresParams->nHeavyCompression); ++ updateDrcWrapper = true; ++ mDrcCompressMode = aacPresParams->nHeavyCompression; ++ } ++ if (aacPresParams->nTargetReferenceLevel >= -1) { ++ ALOGV("set nTargetReferenceLevel=%d", aacPresParams->nTargetReferenceLevel); ++ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_DESIRED_TARGET, ++ aacPresParams->nTargetReferenceLevel); ++ updateDrcWrapper = true; ++ mDrcTargetRefLevel = aacPresParams->nTargetReferenceLevel; ++ } ++ if (aacPresParams->nEncodedTargetLevel >= 0) { ++ ALOGV("set nEncodedTargetLevel=%d", aacPresParams->nEncodedTargetLevel); ++ mDrcWrap.setParam(DRC_PRES_MODE_WRAP_ENCODER_TARGET, ++ aacPresParams->nEncodedTargetLevel); ++ updateDrcWrapper = true; ++ mDrcEncTargetLevel = aacPresParams->nEncodedTargetLevel; ++ } ++ if (aacPresParams->nPCMLimiterEnable >= 0) { ++ aacDecoder_SetParam(mAACDecoder, AAC_PCM_LIMITER_ENABLE, ++ (aacPresParams->nPCMLimiterEnable != 0)); ++ } ++ if (aacPresParams ->nDrcOutputLoudness != DRC_DEFAULT_MOBILE_OUTPUT_LOUDNESS) { ++ mDrcOutputLoudness = aacPresParams ->nDrcOutputLoudness; ++ } ++ if (updateDrcWrapper) { ++ mDrcWrap.update(); ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalSetParameter(index, params); ++ } ++} ++ ++bool SoftAAC2::isConfigured() const { ++ return mInputBufferCount > 0; ++} ++ ++bool SoftAAC2::outputDelayRingBufferPutSamples(INT_PCM *samples, int32_t numSamples) { ++ if (numSamples == 0) { ++ return true; ++ } ++ if (outputDelayRingBufferSpaceLeft() < numSamples) { ++ ALOGE("RING BUFFER WOULD OVERFLOW"); ++ return false; ++ } ++ if (mOutputDelayRingBufferWritePos + numSamples <= mOutputDelayRingBufferSize ++ && (mOutputDelayRingBufferReadPos <= mOutputDelayRingBufferWritePos ++ || mOutputDelayRingBufferReadPos > mOutputDelayRingBufferWritePos + numSamples)) { ++ // faster memcopy loop without checks, if the preconditions allow this ++ for (int32_t i = 0; i < numSamples; i++) { ++ mOutputDelayRingBuffer[mOutputDelayRingBufferWritePos++] = samples[i]; ++ } ++ ++ if (mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferSize) { ++ mOutputDelayRingBufferWritePos -= mOutputDelayRingBufferSize; ++ } ++ } else { ++ ALOGV("slow SoftAAC2::outputDelayRingBufferPutSamples()"); ++ ++ for (int32_t i = 0; i < numSamples; i++) { ++ mOutputDelayRingBuffer[mOutputDelayRingBufferWritePos] = samples[i]; ++ mOutputDelayRingBufferWritePos++; ++ if (mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferSize) { ++ mOutputDelayRingBufferWritePos -= mOutputDelayRingBufferSize; ++ } ++ } ++ } ++ mOutputDelayRingBufferFilled += numSamples; ++ return true; ++} ++ ++int32_t SoftAAC2::outputDelayRingBufferGetSamples(INT_PCM *samples, int32_t numSamples) { ++ ++ if (numSamples > mOutputDelayRingBufferFilled) { ++ ALOGE("RING BUFFER WOULD UNDERRUN"); ++ return -1; ++ } ++ ++ if (mOutputDelayRingBufferReadPos + numSamples <= mOutputDelayRingBufferSize ++ && (mOutputDelayRingBufferWritePos < mOutputDelayRingBufferReadPos ++ || mOutputDelayRingBufferWritePos >= mOutputDelayRingBufferReadPos + numSamples)) { ++ // faster memcopy loop without checks, if the preconditions allow this ++ if (samples != 0) { ++ for (int32_t i = 0; i < numSamples; i++) { ++ samples[i] = mOutputDelayRingBuffer[mOutputDelayRingBufferReadPos++]; ++ } ++ } else { ++ mOutputDelayRingBufferReadPos += numSamples; ++ } ++ if (mOutputDelayRingBufferReadPos >= mOutputDelayRingBufferSize) { ++ mOutputDelayRingBufferReadPos -= mOutputDelayRingBufferSize; ++ } ++ } else { ++ ALOGV("slow SoftAAC2::outputDelayRingBufferGetSamples()"); ++ ++ for (int32_t i = 0; i < numSamples; i++) { ++ if (samples != 0) { ++ samples[i] = mOutputDelayRingBuffer[mOutputDelayRingBufferReadPos]; ++ } ++ mOutputDelayRingBufferReadPos++; ++ if (mOutputDelayRingBufferReadPos >= mOutputDelayRingBufferSize) { ++ mOutputDelayRingBufferReadPos -= mOutputDelayRingBufferSize; ++ } ++ } ++ } ++ mOutputDelayRingBufferFilled -= numSamples; ++ return numSamples; ++} ++ ++int32_t SoftAAC2::outputDelayRingBufferSamplesAvailable() { ++ return mOutputDelayRingBufferFilled; ++} ++ ++int32_t SoftAAC2::outputDelayRingBufferSpaceLeft() { ++ return mOutputDelayRingBufferSize - outputDelayRingBufferSamplesAvailable(); ++} ++ ++ ++void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { ++ if (mSignalledError || mOutputPortSettingsChange != NONE) { ++ return; ++ } ++ ++ UCHAR* inBuffer[FILEREAD_MAX_LAYERS]; ++ UINT inBufferLength[FILEREAD_MAX_LAYERS] = {0}; ++ UINT bytesValid[FILEREAD_MAX_LAYERS] = {0}; ++ ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ ++ while ((!inQueue.empty() || mEndOfInput) && !outQueue.empty()) { ++ if (!inQueue.empty()) { ++ INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT]; ++ BufferInfo *inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++ ++ mEndOfInput = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0; ++ ++ if (mInputBufferCount == 0 && !(inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) { ++ ALOGE("first buffer should have OMX_BUFFERFLAG_CODECCONFIG set"); ++ inHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG; ++ } ++ if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) != 0) { ++ BufferInfo *inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++ ++ inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; ++ inBufferLength[0] = inHeader->nFilledLen; ++ ++ AAC_DECODER_ERROR decoderErr = ++ aacDecoder_ConfigRaw(mAACDecoder, ++ inBuffer, ++ inBufferLength); ++ ++ if (decoderErr != AAC_DEC_OK) { ++ ALOGW("aacDecoder_ConfigRaw decoderErr = 0x%4.4x", decoderErr); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); ++ return; ++ } ++ ++ mInputBufferCount++; ++ mOutputBufferCount++; // fake increase of outputBufferCount to keep the counters aligned ++ ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ mLastInHeader = NULL; ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ ++ // Only send out port settings changed event if both sample rate ++ // and numChannels are valid. ++ if (mStreamInfo->sampleRate && mStreamInfo->numChannels) { ++ ALOGI("Initially configuring decoder: %d Hz, %d channels", ++ mStreamInfo->sampleRate, ++ mStreamInfo->numChannels); ++ ++ notify(OMX_EventPortSettingsChanged, 1, 0, NULL); ++ mOutputPortSettingsChange = AWAITING_DISABLED; ++ } ++ return; ++ } ++ ++ if (inHeader->nFilledLen == 0) { ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ mLastInHeader = NULL; ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ continue; ++ } ++ ++ if (mIsADTS) { ++ size_t adtsHeaderSize = 0; ++ // skip 30 bits, aac_frame_length follows. ++ // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll????? ++ ++ const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset; ++ ++ bool signalError = false; ++ if (inHeader->nFilledLen < 7) { ++ ALOGE("Audio data too short to contain even the ADTS header. " ++ "Got %d bytes.", inHeader->nFilledLen); ++ hexdump(adtsHeader, inHeader->nFilledLen); ++ signalError = true; ++ } else { ++ bool protectionAbsent = (adtsHeader[1] & 1); ++ ++ unsigned aac_frame_length = ++ ((adtsHeader[3] & 3) << 11) ++ | (adtsHeader[4] << 3) ++ | (adtsHeader[5] >> 5); ++ ++ if (inHeader->nFilledLen < aac_frame_length) { ++ ALOGE("Not enough audio data for the complete frame. " ++ "Got %d bytes, frame size according to the ADTS " ++ "header is %u bytes.", ++ inHeader->nFilledLen, aac_frame_length); ++ hexdump(adtsHeader, inHeader->nFilledLen); ++ signalError = true; ++ } else { ++ adtsHeaderSize = (protectionAbsent ? 7 : 9); ++ if (aac_frame_length < adtsHeaderSize) { ++ signalError = true; ++ } else { ++ inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize; ++ inBufferLength[0] = aac_frame_length - adtsHeaderSize; ++ ++ inHeader->nOffset += adtsHeaderSize; ++ inHeader->nFilledLen -= adtsHeaderSize; ++ } ++ } ++ } ++ ++ if (signalError) { ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorStreamCorrupt, ERROR_MALFORMED, NULL); ++ return; ++ } ++ ++ // insert buffer size and time stamp ++ mBufferSizes.add(inBufferLength[0]); ++ if (mLastInHeader != inHeader) { ++ mBufferTimestamps.add(inHeader->nTimeStamp); ++ mLastInHeader = inHeader; ++ } else { ++ int64_t currentTime = mBufferTimestamps.top(); ++ currentTime += mStreamInfo->aacSamplesPerFrame * ++ 1000000LL / mStreamInfo->aacSampleRate; ++ mBufferTimestamps.add(currentTime); ++ } ++ } else { ++ inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; ++ inBufferLength[0] = inHeader->nFilledLen; ++ mLastInHeader = inHeader; ++ mBufferTimestamps.add(inHeader->nTimeStamp); ++ mBufferSizes.add(inHeader->nFilledLen); ++ } ++ ++ // Fill and decode ++ bytesValid[0] = inBufferLength[0]; ++ ++ INT prevSampleRate = mStreamInfo->sampleRate; ++ INT prevNumChannels = mStreamInfo->numChannels; ++ ++ aacDecoder_Fill(mAACDecoder, ++ inBuffer, ++ inBufferLength, ++ bytesValid); ++ ++ // run DRC check ++ mDrcWrap.submitStreamData(mStreamInfo); ++ mDrcWrap.update(); ++ ++ UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; ++ inHeader->nFilledLen -= inBufferUsedLength; ++ inHeader->nOffset += inBufferUsedLength; ++ ++ AAC_DECODER_ERROR decoderErr; ++ int numLoops = 0; ++ do { ++ if (outputDelayRingBufferSpaceLeft() < ++ (mStreamInfo->frameSize * mStreamInfo->numChannels)) { ++ ALOGV("skipping decode: not enough space left in ringbuffer"); ++ break; ++ } ++ ++ int numConsumed = mStreamInfo->numTotalBytes; ++ decoderErr = aacDecoder_DecodeFrame(mAACDecoder, ++ tmpOutBuffer, ++ 2048 * MAX_CHANNEL_COUNT, ++ 0 /* flags */); ++ ++ numConsumed = mStreamInfo->numTotalBytes - numConsumed; ++ numLoops++; ++ ++ if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { ++ break; ++ } ++ mDecodedSizes.add(numConsumed); ++ ++ if (decoderErr != AAC_DEC_OK) { ++ ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr); ++ } ++ ++ if (bytesValid[0] != 0) { ++ ALOGE("bytesValid[0] != 0 should never happen"); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ ++ size_t numOutBytes = ++ mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; ++ ++ if (decoderErr == AAC_DEC_OK) { ++ if (!outputDelayRingBufferPutSamples(tmpOutBuffer, ++ mStreamInfo->frameSize * mStreamInfo->numChannels)) { ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); ++ return; ++ } ++ } else { ++ ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr); ++ ++ memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow ++ ++ if (!outputDelayRingBufferPutSamples(tmpOutBuffer, ++ mStreamInfo->frameSize * mStreamInfo->numChannels)) { ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); ++ return; ++ } ++ ++ // Discard input buffer. ++ if (inHeader) { ++ inHeader->nFilledLen = 0; ++ } ++ ++ aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); ++ ++ // After an error, replace the last entry in mBufferSizes with the sum of the ++ // last entries from mDecodedSizes to resynchronize the in/out lists. ++ mBufferSizes.pop(); ++ int n = 0; ++ for (int i = 0; i < numLoops; i++) { ++ n += mDecodedSizes.itemAt(mDecodedSizes.size() - numLoops + i); ++ } ++ mBufferSizes.add(n); ++ ++ // fall through ++ } ++ ++ if ( mDrcOutputLoudness != mStreamInfo->outputLoudness) { ++ ALOGD("update Loudness, before = %d, now = %d", mDrcOutputLoudness, mStreamInfo->outputLoudness); ++ mDrcOutputLoudness = mStreamInfo->outputLoudness; ++ } ++ ++ /* ++ * AAC+/eAAC+ streams can be signalled in two ways: either explicitly ++ * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual ++ * rate system and the sampling rate in the final output is actually ++ * doubled compared with the core AAC decoder sampling rate. ++ * ++ * Explicit signalling is done by explicitly defining SBR audio object ++ * type in the bitstream. Implicit signalling is done by embedding ++ * SBR content in AAC extension payload specific to SBR, and hence ++ * requires an AAC decoder to perform pre-checks on actual audio frames. ++ * ++ * Thus, we could not say for sure whether a stream is ++ * AAC+/eAAC+ until the first data frame is decoded. ++ */ ++ if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) { ++ if ((mInputBufferCount > 2) && (mOutputBufferCount <= 1)) { ++ ALOGW("Invalid AAC stream"); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); ++ return; ++ } ++ } else if ((mStreamInfo->sampleRate != prevSampleRate) || ++ (mStreamInfo->numChannels != prevNumChannels)) { ++ ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels", ++ prevSampleRate, mStreamInfo->sampleRate, ++ prevNumChannels, mStreamInfo->numChannels); ++ ++ notify(OMX_EventPortSettingsChanged, 1, 0, NULL); ++ mOutputPortSettingsChange = AWAITING_DISABLED; ++ ++ if (inHeader && inHeader->nFilledLen == 0) { ++ inInfo->mOwnedByUs = false; ++ mInputBufferCount++; ++ inQueue.erase(inQueue.begin()); ++ mLastInHeader = NULL; ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ } ++ return; ++ } ++ if (inHeader && inHeader->nFilledLen == 0) { ++ inInfo->mOwnedByUs = false; ++ mInputBufferCount++; ++ inQueue.erase(inQueue.begin()); ++ mLastInHeader = NULL; ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ } else { ++ ALOGV("inHeader->nFilledLen = %d", inHeader ? inHeader->nFilledLen : 0); ++ } ++ } while (decoderErr == AAC_DEC_OK); ++ } ++ ++ int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels; ++ ++ if (!mEndOfInput && mOutputDelayCompensated < outputDelay) { ++ // discard outputDelay at the beginning ++ int32_t toCompensate = outputDelay - mOutputDelayCompensated; ++ int32_t discard = outputDelayRingBufferSamplesAvailable(); ++ if (discard > toCompensate) { ++ discard = toCompensate; ++ } ++ int32_t discarded = outputDelayRingBufferGetSamples(0, discard); ++ mOutputDelayCompensated += discarded; ++ continue; ++ } ++ ++ if (mEndOfInput) { ++ while (mOutputDelayCompensated > 0) { ++ // a buffer big enough for MAX_CHANNEL_COUNT channels of decoded HE-AAC ++ INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT]; ++ ++ // run DRC check ++ mDrcWrap.submitStreamData(mStreamInfo); ++ mDrcWrap.update(); ++ ++ AAC_DECODER_ERROR decoderErr = ++ aacDecoder_DecodeFrame(mAACDecoder, ++ tmpOutBuffer, ++ 2048 * MAX_CHANNEL_COUNT, ++ AACDEC_FLUSH); ++ if (decoderErr != AAC_DEC_OK) { ++ ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr); ++ } ++ ++ int32_t tmpOutBufferSamples = mStreamInfo->frameSize * mStreamInfo->numChannels; ++ if (tmpOutBufferSamples > mOutputDelayCompensated) { ++ tmpOutBufferSamples = mOutputDelayCompensated; ++ } ++ outputDelayRingBufferPutSamples(tmpOutBuffer, tmpOutBufferSamples); ++ mOutputDelayCompensated -= tmpOutBufferSamples; ++ } ++ } ++ ++ while (!outQueue.empty() ++ && outputDelayRingBufferSamplesAvailable() ++ >= mStreamInfo->frameSize * mStreamInfo->numChannels) { ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ ++ if (outHeader->nOffset != 0) { ++ ALOGE("outHeader->nOffset != 0 is not handled"); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ ++ INT_PCM *outBuffer = ++ reinterpret_cast(outHeader->pBuffer + outHeader->nOffset); ++ int samplesize = mStreamInfo->numChannels * sizeof(int16_t); ++ if (outHeader->nOffset ++ + mStreamInfo->frameSize * samplesize ++ > outHeader->nAllocLen) { ++ ALOGE("buffer overflow"); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ ++ } ++ ++ int available = outputDelayRingBufferSamplesAvailable(); ++ int numSamples = outHeader->nAllocLen / sizeof(int16_t); ++ if (numSamples > available) { ++ numSamples = available; ++ } ++ int64_t currentTime = 0; ++ if (available) { ++ ++ int numFrames = numSamples / (mStreamInfo->frameSize * mStreamInfo->numChannels); ++ numSamples = numFrames * (mStreamInfo->frameSize * mStreamInfo->numChannels); ++ ++ ALOGV("%d samples available (%d), or %d frames", ++ numSamples, available, numFrames); ++ int64_t *nextTimeStamp = &mBufferTimestamps.editItemAt(0); ++ currentTime = *nextTimeStamp; ++ int32_t *currentBufLeft = &mBufferSizes.editItemAt(0); ++ for (int i = 0; i < numFrames; i++) { ++ int32_t decodedSize = mDecodedSizes.itemAt(0); ++ mDecodedSizes.removeAt(0); ++ ALOGV("decoded %d of %d", decodedSize, *currentBufLeft); ++ if (*currentBufLeft > decodedSize) { ++ // adjust/interpolate next time stamp ++ *currentBufLeft -= decodedSize; ++ *nextTimeStamp += mStreamInfo->aacSamplesPerFrame * ++ 1000000LL / mStreamInfo->aacSampleRate; ++ ALOGV("adjusted nextTimeStamp/size to %lld/%d", ++ (long long) *nextTimeStamp, *currentBufLeft); ++ } else { ++ // move to next timestamp in list ++ if (mBufferTimestamps.size() > 0) { ++ mBufferTimestamps.removeAt(0); ++ nextTimeStamp = &mBufferTimestamps.editItemAt(0); ++ mBufferSizes.removeAt(0); ++ currentBufLeft = &mBufferSizes.editItemAt(0); ++ ALOGV("moved to next time/size: %lld/%d", ++ (long long) *nextTimeStamp, *currentBufLeft); ++ } ++ // try to limit output buffer size to match input buffers ++ // (e.g when an input buffer contained 4 "sub" frames, output ++ // at most 4 decoded units in the corresponding output buffer) ++ // This is optional. Remove the next three lines to fill the output ++ // buffer with as many units as available. ++ numFrames = i + 1; ++ numSamples = numFrames * mStreamInfo->frameSize * mStreamInfo->numChannels; ++ break; ++ } ++ } ++ ++ ALOGV("getting %d from ringbuffer", numSamples); ++ int32_t ns = outputDelayRingBufferGetSamples(outBuffer, numSamples); ++ if (ns != numSamples) { ++ ALOGE("not a complete frame of samples available"); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ } ++ ++ outHeader->nFilledLen = numSamples * sizeof(int16_t); ++ ++ if (mEndOfInput && !outQueue.empty() && outputDelayRingBufferSamplesAvailable() == 0) { ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ mEndOfOutput = true; ++ } else { ++ outHeader->nFlags = 0; ++ } ++ ++ outHeader->nTimeStamp = currentTime; ++ ++ mOutputBufferCount++; ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ outInfo = NULL; ++ ALOGV("out timestamp %lld / %d", outHeader->nTimeStamp, outHeader->nFilledLen); ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ } ++ ++ if (mEndOfInput) { ++ int ringBufAvail = outputDelayRingBufferSamplesAvailable(); ++ if (!outQueue.empty() ++ && ringBufAvail < mStreamInfo->frameSize * mStreamInfo->numChannels) { ++ if (!mEndOfOutput) { ++ // send partial or empty block signaling EOS ++ mEndOfOutput = true; ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ ++ INT_PCM *outBuffer = reinterpret_cast(outHeader->pBuffer ++ + outHeader->nOffset); ++ int32_t ns = outputDelayRingBufferGetSamples(outBuffer, ringBufAvail); ++ if (ns < 0) { ++ ns = 0; ++ } ++ outHeader->nFilledLen = ns; ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ ++ outHeader->nTimeStamp = mBufferTimestamps.itemAt(0); ++ mBufferTimestamps.clear(); ++ mBufferSizes.clear(); ++ mDecodedSizes.clear(); ++ ++ mOutputBufferCount++; ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ outInfo = NULL; ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ } ++ break; // if outQueue not empty but no more output ++ } ++ } ++ } ++} ++ ++void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { ++ if (portIndex == 0) { ++ // Make sure that the next buffer output does not still ++ // depend on fragments from the last one decoded. ++ // drain all existing data ++ drainDecoder(); ++ mBufferTimestamps.clear(); ++ mBufferSizes.clear(); ++ mDecodedSizes.clear(); ++ mLastInHeader = NULL; ++ mEndOfInput = false; ++ } else { ++ int avail; ++ while ((avail = outputDelayRingBufferSamplesAvailable()) > 0) { ++ if (avail > mStreamInfo->frameSize * mStreamInfo->numChannels) { ++ avail = mStreamInfo->frameSize * mStreamInfo->numChannels; ++ } ++ int32_t ns = outputDelayRingBufferGetSamples(0, avail); ++ if (ns != avail) { ++ ALOGW("not a complete frame of samples available"); ++ break; ++ } ++ mOutputBufferCount++; ++ } ++ mOutputDelayRingBufferReadPos = mOutputDelayRingBufferWritePos; ++ mEndOfOutput = false; ++ } ++} ++ ++void SoftAAC2::drainDecoder() { ++ // flush decoder until outputDelay is compensated ++ while (mOutputDelayCompensated > 0) { ++ // a buffer big enough for MAX_CHANNEL_COUNT channels of decoded HE-AAC ++ INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT]; ++ ++ // run DRC check ++ mDrcWrap.submitStreamData(mStreamInfo); ++ mDrcWrap.update(); ++ ++ AAC_DECODER_ERROR decoderErr = ++ aacDecoder_DecodeFrame(mAACDecoder, ++ tmpOutBuffer, ++ 2048 * MAX_CHANNEL_COUNT, ++ AACDEC_FLUSH); ++ if (decoderErr != AAC_DEC_OK) { ++ ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr); ++ } ++ ++ int32_t tmpOutBufferSamples = mStreamInfo->frameSize * mStreamInfo->numChannels; ++ if (tmpOutBufferSamples > mOutputDelayCompensated) { ++ tmpOutBufferSamples = mOutputDelayCompensated; ++ } ++ outputDelayRingBufferPutSamples(tmpOutBuffer, tmpOutBufferSamples); ++ ++ mOutputDelayCompensated -= tmpOutBufferSamples; ++ } ++} ++ ++void SoftAAC2::onReset() { ++ drainDecoder(); ++ // reset the "configured" state ++ mInputBufferCount = 0; ++ mOutputBufferCount = 0; ++ mOutputDelayCompensated = 0; ++ mOutputDelayRingBufferWritePos = 0; ++ mOutputDelayRingBufferReadPos = 0; ++ mOutputDelayRingBufferFilled = 0; ++ mEndOfInput = false; ++ mEndOfOutput = false; ++ mBufferTimestamps.clear(); ++ mBufferSizes.clear(); ++ mDecodedSizes.clear(); ++ mLastInHeader = NULL; ++ ++ // To make the codec behave the same before and after a reset, we need to invalidate the ++ // streaminfo struct. This does that: ++ mStreamInfo->sampleRate = 0; // TODO: mStreamInfo is read only ++ ++ mSignalledError = false; ++ mOutputPortSettingsChange = NONE; ++} ++ ++void SoftAAC2::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { ++ if (portIndex != 1) { ++ return; ++ } ++ ++ switch (mOutputPortSettingsChange) { ++ case NONE: ++ break; ++ ++ case AWAITING_DISABLED: ++ { ++ CHECK(!enabled); ++ mOutputPortSettingsChange = AWAITING_ENABLED; ++ break; ++ } ++ ++ default: ++ { ++ CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); ++ CHECK(enabled); ++ mOutputPortSettingsChange = NONE; ++ break; ++ } ++ } ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ return new android::SoftAAC2(name, callbacks, appData, component); ++} +diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h +new file mode 100644 +index 0000000..9f98aa1 +--- /dev/null ++++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h +@@ -0,0 +1,109 @@ ++/* ++ * Copyright (C) 2012 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 SOFT_AAC_2_H_ ++#define SOFT_AAC_2_H_ ++ ++#include ++ ++#include "aacdecoder_lib.h" ++#include "DrcPresModeWrap.h" ++ ++namespace android { ++ ++struct SoftAAC2 : public SimpleSoftOMXComponent { ++ SoftAAC2(const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++protected: ++ virtual ~SoftAAC2(); ++ ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params); ++ ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ virtual void onPortFlushCompleted(OMX_U32 portIndex); ++ virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled); ++ virtual void onReset(); ++ ++private: ++ enum { ++ kNumInputBuffers = 4, ++ kNumOutputBuffers = 4, ++ kNumDelayBlocksMax = 8, ++ }; ++ ++ HANDLE_AACDECODER mAACDecoder; ++ CStreamInfo *mStreamInfo; ++ bool mIsADTS; ++ bool mIsFirst; ++ size_t mInputBufferCount; ++ size_t mOutputBufferCount; ++ bool mSignalledError; ++ OMX_BUFFERHEADERTYPE *mLastInHeader; ++ Vector mBufferSizes; ++ Vector mDecodedSizes; ++ Vector mBufferTimestamps; ++ ++ CDrcPresModeWrapper mDrcWrap; ++ ++ enum { ++ NONE, ++ AWAITING_DISABLED, ++ AWAITING_ENABLED ++ } mOutputPortSettingsChange; ++ ++ void initPorts(); ++ status_t initDecoder(); ++ bool isConfigured() const; ++ void drainDecoder(); ++ ++// delay compensation ++ bool mEndOfInput; ++ bool mEndOfOutput; ++ int32_t mOutputDelayCompensated; ++ int32_t mOutputDelayRingBufferSize; ++ int16_t *mOutputDelayRingBuffer; ++ int32_t mOutputDelayRingBufferWritePos; ++ int32_t mOutputDelayRingBufferReadPos; ++ int32_t mOutputDelayRingBufferFilled; ++ ++ //drc ++ int32_t mDrcCompressMode; ++ int32_t mDrcTargetRefLevel; ++ int32_t mDrcEncTargetLevel; ++ int32_t mDrcBoostFactor; ++ int32_t mDrcAttenuationFactor; ++ int32_t mDrcEffectType; ++ int32_t mDrcAlbumMode; ++ int32_t mDrcOutputLoudness; ++ ++ bool outputDelayRingBufferPutSamples(INT_PCM *samples, int numSamples); ++ int32_t outputDelayRingBufferGetSamples(INT_PCM *samples, int numSamples); ++ int32_t outputDelayRingBufferSamplesAvailable(); ++ int32_t outputDelayRingBufferSpaceLeft(); ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftAAC2); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_AAC_2_H_ +diff --git a/media/libstagefright/codecs/aacdec/exports.lds b/media/libstagefright/codecs/aacdec/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/aacdec/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/aacenc/Android.bp b/media/libstagefright/codecs/aacenc/Android.bp +new file mode 100644 +index 0000000..793125f +--- /dev/null ++++ b/media/libstagefright/codecs/aacenc/Android.bp +@@ -0,0 +1,37 @@ ++package { ++ default_applicable_licenses: [ ++ "frameworks_av_media_libstagefright_codecs_aacenc_license", ++ ], ++} ++ ++// Added automatically by a large-scale-change ++// See: http://go/android-license-faq ++license { ++ name: "frameworks_av_media_libstagefright_codecs_aacenc_license", ++ visibility: [":__subpackages__"], ++ license_kinds: [ ++ "SPDX-license-identifier-Apache-2.0", ++ ], ++ license_text: [ ++ "NOTICE", ++ ], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_aacenc", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: ["SoftAACEncoder2.cpp"], ++ ++ version_script: "exports.lds", ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ "unsigned-integer-overflow", ++ ], ++ cfi: true, ++ }, ++ ++ static_libs: ["libFraunhoferAAC"], ++} +diff --git a/media/libstagefright/codecs/aacenc/MODULE_LICENSE_APACHE2 b/media/libstagefright/codecs/aacenc/MODULE_LICENSE_APACHE2 +new file mode 100644 +index 0000000..e69de29 +diff --git a/media/libstagefright/codecs/aacenc/NOTICE b/media/libstagefright/codecs/aacenc/NOTICE +new file mode 100644 +index 0000000..c5b1efa +--- /dev/null ++++ b/media/libstagefright/codecs/aacenc/NOTICE +@@ -0,0 +1,190 @@ ++ ++ Copyright (c) 2005-2008, 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. ++ ++ 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. ++ ++ ++ Apache License ++ Version 2.0, January 2004 ++ http://www.apache.org/licenses/ ++ ++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION ++ ++ 1. Definitions. ++ ++ "License" shall mean the terms and conditions for use, reproduction, ++ and distribution as defined by Sections 1 through 9 of this document. ++ ++ "Licensor" shall mean the copyright owner or entity authorized by ++ the copyright owner that is granting the License. ++ ++ "Legal Entity" shall mean the union of the acting entity and all ++ other entities that control, are controlled by, or are under common ++ control with that entity. For the purposes of this definition, ++ "control" means (i) the power, direct or indirect, to cause the ++ direction or management of such entity, whether by contract or ++ otherwise, or (ii) ownership of fifty percent (50%) or more of the ++ outstanding shares, or (iii) beneficial ownership of such entity. ++ ++ "You" (or "Your") shall mean an individual or Legal Entity ++ exercising permissions granted by this License. ++ ++ "Source" form shall mean the preferred form for making modifications, ++ including but not limited to software source code, documentation ++ source, and configuration files. ++ ++ "Object" form shall mean any form resulting from mechanical ++ transformation or translation of a Source form, including but ++ not limited to compiled object code, generated documentation, ++ and conversions to other media types. ++ ++ "Work" shall mean the work of authorship, whether in Source or ++ Object form, made available under the License, as indicated by a ++ copyright notice that is included in or attached to the work ++ (an example is provided in the Appendix below). ++ ++ "Derivative Works" shall mean any work, whether in Source or Object ++ form, that is based on (or derived from) the Work and for which the ++ editorial revisions, annotations, elaborations, or other modifications ++ represent, as a whole, an original work of authorship. For the purposes ++ of this License, Derivative Works shall not include works that remain ++ separable from, or merely link (or bind by name) to the interfaces of, ++ the Work and Derivative Works thereof. ++ ++ "Contribution" shall mean any work of authorship, including ++ the original version of the Work and any modifications or additions ++ to that Work or Derivative Works thereof, that is intentionally ++ submitted to Licensor for inclusion in the Work by the copyright owner ++ or by an individual or Legal Entity authorized to submit on behalf of ++ the copyright owner. For the purposes of this definition, "submitted" ++ means any form of electronic, verbal, or written communication sent ++ to the Licensor or its representatives, including but not limited to ++ communication on electronic mailing lists, source code control systems, ++ and issue tracking systems that are managed by, or on behalf of, the ++ Licensor for the purpose of discussing and improving the Work, but ++ excluding communication that is conspicuously marked or otherwise ++ designated in writing by the copyright owner as "Not a Contribution." ++ ++ "Contributor" shall mean Licensor and any individual or Legal Entity ++ on behalf of whom a Contribution has been received by Licensor and ++ subsequently incorporated within the Work. ++ ++ 2. Grant of Copyright License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ copyright license to reproduce, prepare Derivative Works of, ++ publicly display, publicly perform, sublicense, and distribute the ++ Work and such Derivative Works in Source or Object form. ++ ++ 3. Grant of Patent License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ (except as stated in this section) patent license to make, have made, ++ use, offer to sell, sell, import, and otherwise transfer the Work, ++ where such license applies only to those patent claims licensable ++ by such Contributor that are necessarily infringed by their ++ Contribution(s) alone or by combination of their Contribution(s) ++ with the Work to which such Contribution(s) was submitted. If You ++ institute patent litigation against any entity (including a ++ cross-claim or counterclaim in a lawsuit) alleging that the Work ++ or a Contribution incorporated within the Work constitutes direct ++ or contributory patent infringement, then any patent licenses ++ granted to You under this License for that Work shall terminate ++ as of the date such litigation is filed. ++ ++ 4. Redistribution. You may reproduce and distribute copies of the ++ Work or Derivative Works thereof in any medium, with or without ++ modifications, and in Source or Object form, provided that You ++ meet the following conditions: ++ ++ (a) You must give any other recipients of the Work or ++ Derivative Works a copy of this License; and ++ ++ (b) You must cause any modified files to carry prominent notices ++ stating that You changed the files; and ++ ++ (c) You must retain, in the Source form of any Derivative Works ++ that You distribute, all copyright, patent, trademark, and ++ attribution notices from the Source form of the Work, ++ excluding those notices that do not pertain to any part of ++ the Derivative Works; and ++ ++ (d) If the Work includes a "NOTICE" text file as part of its ++ distribution, then any Derivative Works that You distribute must ++ include a readable copy of the attribution notices contained ++ within such NOTICE file, excluding those notices that do not ++ pertain to any part of the Derivative Works, in at least one ++ of the following places: within a NOTICE text file distributed ++ as part of the Derivative Works; within the Source form or ++ documentation, if provided along with the Derivative Works; or, ++ within a display generated by the Derivative Works, if and ++ wherever such third-party notices normally appear. The contents ++ of the NOTICE file are for informational purposes only and ++ do not modify the License. You may add Your own attribution ++ notices within Derivative Works that You distribute, alongside ++ or as an addendum to the NOTICE text from the Work, provided ++ that such additional attribution notices cannot be construed ++ as modifying the License. ++ ++ You may add Your own copyright statement to Your modifications and ++ may provide additional or different license terms and conditions ++ for use, reproduction, or distribution of Your modifications, or ++ for any such Derivative Works as a whole, provided Your use, ++ reproduction, and distribution of the Work otherwise complies with ++ the conditions stated in this License. ++ ++ 5. Submission of Contributions. Unless You explicitly state otherwise, ++ any Contribution intentionally submitted for inclusion in the Work ++ by You to the Licensor shall be under the terms and conditions of ++ this License, without any additional terms or conditions. ++ Notwithstanding the above, nothing herein shall supersede or modify ++ the terms of any separate license agreement you may have executed ++ with Licensor regarding such Contributions. ++ ++ 6. Trademarks. This License does not grant permission to use the trade ++ names, trademarks, service marks, or product names of the Licensor, ++ except as required for reasonable and customary use in describing the ++ origin of the Work and reproducing the content of the NOTICE file. ++ ++ 7. Disclaimer of Warranty. Unless required by applicable law or ++ agreed to in writing, Licensor provides the Work (and each ++ Contributor provides its Contributions) on an "AS IS" BASIS, ++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or ++ implied, including, without limitation, any warranties or conditions ++ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A ++ PARTICULAR PURPOSE. You are solely responsible for determining the ++ appropriateness of using or redistributing the Work and assume any ++ risks associated with Your exercise of permissions under this License. ++ ++ 8. Limitation of Liability. In no event and under no legal theory, ++ whether in tort (including negligence), contract, or otherwise, ++ unless required by applicable law (such as deliberate and grossly ++ negligent acts) or agreed to in writing, shall any Contributor be ++ liable to You for damages, including any direct, indirect, special, ++ incidental, or consequential damages of any character arising as a ++ result of this License or out of the use or inability to use the ++ Work (including but not limited to damages for loss of goodwill, ++ work stoppage, computer failure or malfunction, or any and all ++ other commercial damages or losses), even if such Contributor ++ has been advised of the possibility of such damages. ++ ++ 9. Accepting Warranty or Additional Liability. While redistributing ++ the Work or Derivative Works thereof, You may choose to offer, ++ and charge a fee for, acceptance of support, warranty, indemnity, ++ or other liability obligations and/or rights consistent with this ++ License. However, in accepting such obligations, You may act only ++ on Your own behalf and on Your sole responsibility, not on behalf ++ of any other Contributor, and only if You agree to indemnify, ++ defend, and hold each Contributor harmless for any liability ++ incurred by, or claims asserted against, such Contributor by reason ++ of your accepting any such warranty or additional liability. ++ ++ END OF TERMS AND CONDITIONS ++ +diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp +new file mode 100644 +index 0000000..90421b9 +--- /dev/null ++++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp +@@ -0,0 +1,740 @@ ++/* ++ * Copyright (C) 2012 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 "SoftAACEncoder2" ++#include ++#include ++ ++#include "SoftAACEncoder2.h" ++#include ++#include ++ ++#include ++#include ++#include ++ ++namespace android { ++ ++template ++static void InitOMXParams(T *params) { ++ params->nSize = sizeof(T); ++ params->nVersion.s.nVersionMajor = 1; ++ params->nVersion.s.nVersionMinor = 0; ++ params->nVersion.s.nRevision = 0; ++ params->nVersion.s.nStep = 0; ++} ++ ++static const OMX_U32 kSupportedProfiles[] = { ++ OMX_AUDIO_AACObjectLC, ++ OMX_AUDIO_AACObjectHE, ++ OMX_AUDIO_AACObjectHE_PS, ++ OMX_AUDIO_AACObjectLD, ++ OMX_AUDIO_AACObjectELD, ++}; ++ ++SoftAACEncoder2::SoftAACEncoder2( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SimpleSoftOMXComponent(name, callbacks, appData, component), ++ mAACEncoder(NULL), ++ mNumChannels(1), ++ mSampleRate(44100), ++ mBitRate(0), ++ mSBRMode(-1), ++ mSBRRatio(0), ++ mAACProfile(OMX_AUDIO_AACObjectLC), ++ mSentCodecSpecificData(false), ++ mInputSize(0), ++ mInputFrame(NULL), ++ mAllocatedFrameSize(0), ++ mInputTimeUs(-1LL), ++ mSawInputEOS(false), ++ mSignalledError(false) { ++ initPorts(); ++ CHECK_EQ(initEncoder(), (status_t)OK); ++ setAudioParams(); ++} ++ ++SoftAACEncoder2::~SoftAACEncoder2() { ++ aacEncClose(&mAACEncoder); ++ ++ onReset(); ++} ++ ++void SoftAACEncoder2::initPorts() { ++ OMX_PARAM_PORTDEFINITIONTYPE def; ++ InitOMXParams(&def); ++ ++ def.nPortIndex = 0; ++ def.eDir = OMX_DirInput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t) * 2; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 1; ++ ++ def.format.audio.cMIMEType = const_cast("audio/raw"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; ++ ++ addPort(def); ++ ++ def.nPortIndex = 1; ++ def.eDir = OMX_DirOutput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = 8192; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 2; ++ ++ def.format.audio.cMIMEType = const_cast("audio/aac"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingAAC; ++ ++ addPort(def); ++} ++ ++status_t SoftAACEncoder2::initEncoder() { ++ if (AACENC_OK != aacEncOpen(&mAACEncoder, 0, 0)) { ++ ALOGE("Failed to init AAC encoder"); ++ return UNKNOWN_ERROR; ++ } ++ return OK; ++} ++ ++OMX_ERRORTYPE SoftAACEncoder2::internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params) { ++ switch ((OMX_U32) index) { ++ case OMX_IndexParamAudioPortFormat: ++ { ++ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (formatParams->nIndex > 0) { ++ return OMX_ErrorNoMore; ++ } ++ ++ formatParams->eEncoding = ++ (formatParams->nPortIndex == 0) ++ ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAAC; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioAac: ++ { ++ OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = ++ (OMX_AUDIO_PARAM_AACPROFILETYPE *)params; ++ ++ if (!isValidOMXParam(aacParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (aacParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ aacParams->nBitRate = mBitRate; ++ aacParams->nAudioBandWidth = 0; ++ aacParams->nAACtools = 0; ++ aacParams->nAACERtools = 0; ++ aacParams->eAACProfile = (OMX_AUDIO_AACPROFILETYPE) mAACProfile; ++ aacParams->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF; ++ aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo; ++ ++ aacParams->nChannels = mNumChannels; ++ aacParams->nSampleRate = mSampleRate; ++ aacParams->nFrameLength = 0; ++ ++ switch (mSBRMode) { ++ case 1: // sbr on ++ switch (mSBRRatio) { ++ case 0: ++ // set both OMX AAC tool flags ++ aacParams->nAACtools |= OMX_AUDIO_AACToolAndroidSSBR; ++ aacParams->nAACtools |= OMX_AUDIO_AACToolAndroidDSBR; ++ break; ++ case 1: ++ // set single-rate SBR active ++ aacParams->nAACtools |= OMX_AUDIO_AACToolAndroidSSBR; ++ aacParams->nAACtools &= ~OMX_AUDIO_AACToolAndroidDSBR; ++ break; ++ case 2: ++ // set dual-rate SBR active ++ aacParams->nAACtools &= ~OMX_AUDIO_AACToolAndroidSSBR; ++ aacParams->nAACtools |= OMX_AUDIO_AACToolAndroidDSBR; ++ break; ++ default: ++ ALOGE("invalid SBR ratio %d", mSBRRatio); ++ TRESPASS(); ++ } ++ break; ++ case 0: // sbr off ++ case -1: // sbr undefined ++ aacParams->nAACtools &= ~OMX_AUDIO_AACToolAndroidSSBR; ++ aacParams->nAACtools &= ~OMX_AUDIO_AACToolAndroidDSBR; ++ break; ++ default: ++ ALOGE("invalid SBR mode %d", mSBRMode); ++ TRESPASS(); ++ } ++ ++ ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ pcmParams->eNumData = OMX_NumericalDataSigned; ++ pcmParams->eEndian = OMX_EndianBig; ++ pcmParams->bInterleaved = OMX_TRUE; ++ pcmParams->nBitPerSample = 16; ++ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; ++ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; ++ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; ++ ++ pcmParams->nChannels = mNumChannels; ++ pcmParams->nSamplingRate = mSampleRate; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioProfileQuerySupported: ++ { ++ OMX_AUDIO_PARAM_ANDROID_PROFILETYPE *profileParams = ++ (OMX_AUDIO_PARAM_ANDROID_PROFILETYPE *)params; ++ ++ if (!isValidOMXParam(profileParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (profileParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (profileParams->nProfileIndex >= NELEM(kSupportedProfiles)) { ++ return OMX_ErrorNoMore; ++ } ++ ++ profileParams->eProfile = ++ kSupportedProfiles[profileParams->nProfileIndex]; ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalGetParameter(index, params); ++ } ++} ++ ++OMX_ERRORTYPE SoftAACEncoder2::internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamStandardComponentRole: ++ { ++ const OMX_PARAM_COMPONENTROLETYPE *roleParams = ++ (const OMX_PARAM_COMPONENTROLETYPE *)params; ++ ++ if (!isValidOMXParam(roleParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (strncmp((const char *)roleParams->cRole, ++ "audio_encoder.aac", ++ OMX_MAX_STRINGNAME_SIZE - 1)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPortFormat: ++ { ++ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if ((formatParams->nPortIndex == 0 ++ && formatParams->eEncoding != OMX_AUDIO_CodingPCM) ++ || (formatParams->nPortIndex == 1 ++ && formatParams->eEncoding != OMX_AUDIO_CodingAAC)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioAac: ++ { ++ OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = ++ (OMX_AUDIO_PARAM_AACPROFILETYPE *)params; ++ ++ if (!isValidOMXParam(aacParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (aacParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ mBitRate = aacParams->nBitRate; ++ mNumChannels = aacParams->nChannels; ++ mSampleRate = aacParams->nSampleRate; ++ if (aacParams->eAACProfile != OMX_AUDIO_AACObjectNull) { ++ mAACProfile = aacParams->eAACProfile; ++ } ++ ++ if (!(aacParams->nAACtools & OMX_AUDIO_AACToolAndroidSSBR) ++ && !(aacParams->nAACtools & OMX_AUDIO_AACToolAndroidDSBR)) { ++ mSBRMode = 0; ++ mSBRRatio = 0; ++ } else if ((aacParams->nAACtools & OMX_AUDIO_AACToolAndroidSSBR) ++ && !(aacParams->nAACtools & OMX_AUDIO_AACToolAndroidDSBR)) { ++ mSBRMode = 1; ++ mSBRRatio = 1; ++ } else if (!(aacParams->nAACtools & OMX_AUDIO_AACToolAndroidSSBR) ++ && (aacParams->nAACtools & OMX_AUDIO_AACToolAndroidDSBR)) { ++ mSBRMode = 1; ++ mSBRRatio = 2; ++ } else { ++ mSBRMode = -1; // codec default sbr mode ++ mSBRRatio = 0; ++ } ++ ++ if (setAudioParams() != OK) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ mNumChannels = pcmParams->nChannels; ++ mSampleRate = pcmParams->nSamplingRate; ++ if (setAudioParams() != OK) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalSetParameter(index, params); ++ } ++} ++ ++static CHANNEL_MODE getChannelMode(OMX_U32 nChannels) { ++ CHANNEL_MODE chMode = MODE_INVALID; ++ switch (nChannels) { ++ case 1: chMode = MODE_1; break; ++ case 2: chMode = MODE_2; break; ++ case 3: chMode = MODE_1_2; break; ++ case 4: chMode = MODE_1_2_1; break; ++ case 5: chMode = MODE_1_2_2; break; ++ case 6: chMode = MODE_1_2_2_1; break; ++ default: chMode = MODE_INVALID; ++ } ++ return chMode; ++} ++ ++static AUDIO_OBJECT_TYPE getAOTFromProfile(OMX_U32 profile) { ++ if (profile == OMX_AUDIO_AACObjectLC) { ++ return AOT_AAC_LC; ++ } else if (profile == OMX_AUDIO_AACObjectHE) { ++ return AOT_SBR; ++ } else if (profile == OMX_AUDIO_AACObjectHE_PS) { ++ return AOT_PS; ++ } else if (profile == OMX_AUDIO_AACObjectLD) { ++ return AOT_ER_AAC_LD; ++ } else if (profile == OMX_AUDIO_AACObjectELD) { ++ return AOT_ER_AAC_ELD; ++ } else { ++ ALOGW("Unsupported AAC profile - defaulting to AAC-LC"); ++ return AOT_AAC_LC; ++ } ++} ++ ++status_t SoftAACEncoder2::setAudioParams() { ++ // We call this whenever sample rate, number of channels, bitrate or SBR mode change ++ // in reponse to setParameter calls. ++ ++ ALOGV("setAudioParams: %u Hz, %u channels, %u bps, %i sbr mode, %i sbr ratio", ++ mSampleRate, mNumChannels, mBitRate, mSBRMode, mSBRRatio); ++ ++ if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_AOT, ++ getAOTFromProfile(mAACProfile))) { ++ ALOGE("Failed to set AAC encoder parameters"); ++ return UNKNOWN_ERROR; ++ } ++ ++ if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SAMPLERATE, mSampleRate)) { ++ ALOGE("Failed to set AAC encoder parameters"); ++ return UNKNOWN_ERROR; ++ } ++ if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_BITRATE, mBitRate)) { ++ ALOGE("Failed to set AAC encoder parameters"); ++ return UNKNOWN_ERROR; ++ } ++ if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_CHANNELMODE, ++ getChannelMode(mNumChannels))) { ++ ALOGE("Failed to set AAC encoder parameters"); ++ return UNKNOWN_ERROR; ++ } ++ if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_TRANSMUX, TT_MP4_RAW)) { ++ ALOGE("Failed to set AAC encoder parameters"); ++ return UNKNOWN_ERROR; ++ } ++ ++ if (mSBRMode != -1 && mAACProfile == OMX_AUDIO_AACObjectELD) { ++ if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_MODE, mSBRMode)) { ++ ALOGE("Failed to set AAC encoder parameters"); ++ return UNKNOWN_ERROR; ++ } ++ } ++ ++ /* SBR ratio parameter configurations: ++ 0: Default configuration wherein SBR ratio is configured depending on audio object type by ++ the FDK. ++ 1: Downsampled SBR (default for ELD) ++ 2: Dualrate SBR (default for HE-AAC) ++ */ ++ if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_RATIO, mSBRRatio)) { ++ ALOGE("Failed to set AAC encoder parameters"); ++ return UNKNOWN_ERROR; ++ } ++ ++ return OK; ++} ++ ++void SoftAACEncoder2::onQueueFilled(OMX_U32 /* portIndex */) { ++ if (mSignalledError) { ++ return; ++ } ++ ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ ++ if (!mSentCodecSpecificData) { ++ // The very first thing we want to output is the codec specific ++ // data. It does not require any input data but we will need an ++ // output buffer to store it in. ++ ++ if (outQueue.empty()) { ++ return; ++ } ++ ++ if (AACENC_OK != aacEncEncode(mAACEncoder, NULL, NULL, NULL, NULL)) { ++ ALOGE("Unable to initialize encoder for profile / sample-rate / bit-rate / channels"); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ OMX_U32 actualBitRate = aacEncoder_GetParam(mAACEncoder, AACENC_BITRATE); ++ if (mBitRate != actualBitRate) { ++ ALOGW("Requested bitrate %u unsupported, using %u", mBitRate, actualBitRate); ++ } ++ ++ AACENC_InfoStruct encInfo; ++ if (AACENC_OK != aacEncInfo(mAACEncoder, &encInfo)) { ++ ALOGE("Failed to get AAC encoder info"); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ ++ if (outHeader->nOffset + encInfo.confSize > outHeader->nAllocLen) { ++ ALOGE("b/34617444"); ++ android_errorWriteLog(0x534e4554,"34617444"); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ outHeader->nFilledLen = encInfo.confSize; ++ outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG; ++ ++ uint8_t *out = outHeader->pBuffer + outHeader->nOffset; ++ memcpy(out, encInfo.confBuf, encInfo.confSize); ++ ++ outQueue.erase(outQueue.begin()); ++ outInfo->mOwnedByUs = false; ++ notifyFillBufferDone(outHeader); ++ ++ mSentCodecSpecificData = true; ++ } ++ ++ size_t numBytesPerInputFrame = ++ mNumChannels * kNumSamplesPerFrame * sizeof(int16_t); ++ ++ // Limit input size so we only get one ELD frame ++ if (mAACProfile == OMX_AUDIO_AACObjectELD && numBytesPerInputFrame > 512) { ++ numBytesPerInputFrame = 512; ++ } ++ ++ for (;;) { ++ // We do the following until we run out of buffers. ++ ++ while (mInputSize < numBytesPerInputFrame) { ++ // As long as there's still input data to be read we ++ // will drain "kNumSamplesPerFrame * mNumChannels" samples ++ // into the "mInputFrame" buffer and then encode those ++ // as a unit into an output buffer. ++ ++ if (mSawInputEOS || inQueue.empty()) { ++ return; ++ } ++ ++ BufferInfo *inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++ ++ const void *inData = inHeader->pBuffer + inHeader->nOffset; ++ ++ size_t copy = numBytesPerInputFrame - mInputSize; ++ if (copy > inHeader->nFilledLen) { ++ copy = inHeader->nFilledLen; ++ } ++ ++ if (mInputFrame == NULL) { ++ mInputFrame = new int16_t[numBytesPerInputFrame / sizeof(int16_t)]; ++ mAllocatedFrameSize = numBytesPerInputFrame; ++ } else if (mAllocatedFrameSize != numBytesPerInputFrame) { ++ ALOGE("b/34621073: changed size from %d to %d", ++ (int)mAllocatedFrameSize, (int)numBytesPerInputFrame); ++ android_errorWriteLog(0x534e4554,"34621073"); ++ delete mInputFrame; ++ mInputFrame = new int16_t[numBytesPerInputFrame / sizeof(int16_t)]; ++ mAllocatedFrameSize = numBytesPerInputFrame; ++ ++ } ++ ++ if (mInputSize == 0) { ++ mInputTimeUs = inHeader->nTimeStamp; ++ } ++ ++ memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy); ++ mInputSize += copy; ++ ++ inHeader->nOffset += copy; ++ inHeader->nFilledLen -= copy; ++ ++ // "Time" on the input buffer has in effect advanced by the ++ // number of audio frames we just advanced nOffset by. ++ inHeader->nTimeStamp += ++ (copy * 1000000LL / mSampleRate) ++ / (mNumChannels * sizeof(int16_t)); ++ ++ if (inHeader->nFilledLen == 0) { ++ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ mSawInputEOS = true; ++ ++ // Pad any remaining data with zeroes. ++ memset((uint8_t *)mInputFrame + mInputSize, ++ 0, ++ numBytesPerInputFrame - mInputSize); ++ ++ mInputSize = numBytesPerInputFrame; ++ } ++ ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ ++ inData = NULL; ++ inHeader = NULL; ++ inInfo = NULL; ++ } ++ } ++ ++ // At this point we have all the input data necessary to encode ++ // a single frame, all we need is an output buffer to store the result ++ // in. ++ ++ if (outQueue.empty()) { ++ return; ++ } ++ ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ ++ uint8_t *outPtr = (uint8_t *)outHeader->pBuffer + outHeader->nOffset; ++ size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset; ++ ++ AACENC_InArgs inargs; ++ AACENC_OutArgs outargs; ++ memset(&inargs, 0, sizeof(inargs)); ++ memset(&outargs, 0, sizeof(outargs)); ++ inargs.numInSamples = numBytesPerInputFrame / sizeof(int16_t); ++ ++ void* inBuffer[] = { (unsigned char *)mInputFrame }; ++ INT inBufferIds[] = { IN_AUDIO_DATA }; ++ INT inBufferSize[] = { (INT)numBytesPerInputFrame }; ++ INT inBufferElSize[] = { sizeof(int16_t) }; ++ ++ AACENC_BufDesc inBufDesc; ++ inBufDesc.numBufs = sizeof(inBuffer) / sizeof(void*); ++ inBufDesc.bufs = (void**)&inBuffer; ++ inBufDesc.bufferIdentifiers = inBufferIds; ++ inBufDesc.bufSizes = inBufferSize; ++ inBufDesc.bufElSizes = inBufferElSize; ++ ++ void* outBuffer[] = { outPtr }; ++ INT outBufferIds[] = { OUT_BITSTREAM_DATA }; ++ INT outBufferSize[] = { 0 }; ++ INT outBufferElSize[] = { sizeof(UCHAR) }; ++ ++ AACENC_BufDesc outBufDesc; ++ outBufDesc.numBufs = sizeof(outBuffer) / sizeof(void*); ++ outBufDesc.bufs = (void**)&outBuffer; ++ outBufDesc.bufferIdentifiers = outBufferIds; ++ outBufDesc.bufSizes = outBufferSize; ++ outBufDesc.bufElSizes = outBufferElSize; ++ ++ // Encode the mInputFrame, which is treated as a modulo buffer ++ AACENC_ERROR encoderErr = AACENC_OK; ++ size_t nOutputBytes = 0; ++ ++ do { ++ memset(&outargs, 0, sizeof(outargs)); ++ ++ outBuffer[0] = outPtr; ++ outBufferSize[0] = outAvailable - nOutputBytes; ++ ++ encoderErr = aacEncEncode(mAACEncoder, ++ &inBufDesc, ++ &outBufDesc, ++ &inargs, ++ &outargs); ++ ++ if (encoderErr == AACENC_OK) { ++ outPtr += outargs.numOutBytes; ++ nOutputBytes += outargs.numOutBytes; ++ ++ if (outargs.numInSamples > 0) { ++ int numRemainingSamples = inargs.numInSamples - outargs.numInSamples; ++ if (numRemainingSamples > 0) { ++ memmove(mInputFrame, ++ &mInputFrame[outargs.numInSamples], ++ sizeof(int16_t) * numRemainingSamples); ++ } ++ inargs.numInSamples -= outargs.numInSamples; ++ } ++ } ++ } while (encoderErr == AACENC_OK && inargs.numInSamples > 0); ++ ++ outHeader->nFilledLen = nOutputBytes; ++ ++ outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME; ++ ++ if (mSawInputEOS) { ++ // We also tag this output buffer with EOS if it corresponds ++ // to the final input buffer. ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ } ++ ++ outHeader->nTimeStamp = mInputTimeUs; ++ ++#if 0 ++ ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)", ++ nOutputBytes, mInputTimeUs, outHeader->nFlags); ++ ++ hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen); ++#endif ++ ++ outQueue.erase(outQueue.begin()); ++ outInfo->mOwnedByUs = false; ++ notifyFillBufferDone(outHeader); ++ ++ outHeader = NULL; ++ outInfo = NULL; ++ ++ mInputSize = 0; ++ } ++} ++ ++void SoftAACEncoder2::onReset() { ++ delete[] mInputFrame; ++ mInputFrame = NULL; ++ mInputSize = 0; ++ mAllocatedFrameSize = 0; ++ ++ mSentCodecSpecificData = false; ++ mInputTimeUs = -1LL; ++ mSawInputEOS = false; ++ mSignalledError = false; ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ return new android::SoftAACEncoder2(name, callbacks, appData, component); ++} +diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h +new file mode 100644 +index 0000000..681dcf2 +--- /dev/null ++++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h +@@ -0,0 +1,82 @@ ++/* ++ * Copyright (C) 2012 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 SOFT_AAC_ENCODER_2_H_ ++ ++#define SOFT_AAC_ENCODER_2_H_ ++ ++#include ++ ++#include "aacenc_lib.h" ++ ++namespace android { ++ ++struct SoftAACEncoder2 : public SimpleSoftOMXComponent { ++ SoftAACEncoder2( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++protected: ++ virtual ~SoftAACEncoder2(); ++ ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params); ++ ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ ++ virtual void onReset(); ++ ++private: ++ enum { ++ kNumBuffers = 4, ++ kNumSamplesPerFrame = 1024 ++ }; ++ ++ HANDLE_AACENCODER mAACEncoder; ++ ++ OMX_U32 mNumChannels; ++ OMX_U32 mSampleRate; ++ OMX_U32 mBitRate; ++ OMX_S32 mSBRMode; ++ OMX_S32 mSBRRatio; ++ OMX_U32 mAACProfile; ++ ++ bool mSentCodecSpecificData; ++ size_t mInputSize; ++ int16_t *mInputFrame; ++ size_t mAllocatedFrameSize; ++ int64_t mInputTimeUs; ++ ++ bool mSawInputEOS; ++ ++ bool mSignalledError; ++ ++ void initPorts(); ++ status_t initEncoder(); ++ ++ status_t setAudioParams(); ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftAACEncoder2); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_AAC_ENCODER_2_H_ +diff --git a/media/libstagefright/codecs/aacenc/exports.lds b/media/libstagefright/codecs/aacenc/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/aacenc/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/aacenc/patent_disclaimer.txt b/media/libstagefright/codecs/aacenc/patent_disclaimer.txt +new file mode 100644 +index 0000000..b4bf11d +--- /dev/null ++++ b/media/libstagefright/codecs/aacenc/patent_disclaimer.txt +@@ -0,0 +1,9 @@ ++ ++THIS IS NOT A GRANT OF PATENT RIGHTS. ++ ++Google makes no representation or warranty that the codecs for which ++source code is made available hereunder are unencumbered by ++third-party patents. Those intending to use this source code in ++hardware or software products are advised that implementations of ++these codecs, including in open source software or shareware, may ++require patent licenses from the relevant patent holders. +diff --git a/media/libstagefright/codecs/amrnb/dec/Android.bp b/media/libstagefright/codecs/amrnb/dec/Android.bp +new file mode 100644 +index 0000000..2c0954d +--- /dev/null ++++ b/media/libstagefright/codecs/amrnb/dec/Android.bp +@@ -0,0 +1,39 @@ ++//############################################################################### ++ ++package { ++ // See: http://go/android-license-faq ++ // A large-scale-change added 'default_applicable_licenses' to import ++ // all of the 'license_kinds' from "frameworks_av_media_libstagefright_license" ++ // to get the below license kinds: ++ // SPDX-license-identifier-Apache-2.0 ++ default_applicable_licenses: ["frameworks_av_media_libstagefright_license"], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_amrdec", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: ["SoftAMR.cpp"], ++ ++ cflags: [ ++ "-DOSCL_IMPORT_REF=", ++ ], ++ ++ version_script: "exports.lds", ++ ++ //sanitize: { ++ // misc_undefined: [ ++ // "signed-integer-overflow", ++ // ], ++ //}, ++ //LOCAL_SANITIZE := signed-integer-overflow ++ ++ static_libs: [ ++ "libstagefright_amrnbdec", ++ "libstagefright_amrwbdec", ++ ], ++ ++ shared_libs: [ ++ "libstagefright_amrnb_common", ++ ], ++} +diff --git a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp +new file mode 100644 +index 0000000..01da3f8 +--- /dev/null ++++ b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp +@@ -0,0 +1,585 @@ ++/* ++ * Copyright (C) 2011 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 "SoftAMR" ++#include ++ ++#include "SoftAMR.h" ++ ++#include ++ ++namespace android { ++ ++template ++static void InitOMXParams(T *params) { ++ params->nSize = sizeof(T); ++ params->nVersion.s.nVersionMajor = 1; ++ params->nVersion.s.nVersionMinor = 0; ++ params->nVersion.s.nRevision = 0; ++ params->nVersion.s.nStep = 0; ++} ++ ++SoftAMR::SoftAMR( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SimpleSoftOMXComponent(name, callbacks, appData, component), ++ mMode(MODE_NARROW), ++ mState(NULL), ++ mDecoderBuf(NULL), ++ mDecoderCookie(NULL), ++ mInputBufferCount(0), ++ mAnchorTimeUs(0), ++ mNumSamplesOutput(0), ++ mSignalledError(false), ++ mOutputPortSettingsChange(NONE) { ++ if (!strcmp(name, "OMX.google.amrwb.decoder")) { ++ mMode = MODE_WIDE; ++ } else { ++ CHECK(!strcmp(name, "OMX.google.amrnb.decoder")); ++ } ++ ++ initPorts(); ++ CHECK_EQ(initDecoder(), (status_t)OK); ++} ++ ++SoftAMR::~SoftAMR() { ++ if (mMode == MODE_NARROW) { ++ GSMDecodeFrameExit(&mState); ++ mState = NULL; ++ } else { ++ free(mDecoderBuf); ++ mDecoderBuf = NULL; ++ ++ mState = NULL; ++ mDecoderCookie = NULL; ++ } ++} ++ ++void SoftAMR::initPorts() { ++ OMX_PARAM_PORTDEFINITIONTYPE def; ++ InitOMXParams(&def); ++ ++ def.nPortIndex = 0; ++ def.eDir = OMX_DirInput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = 8192; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 1; ++ ++ def.format.audio.cMIMEType = ++ mMode == MODE_NARROW ++ ? const_cast("audio/amr") ++ : const_cast("audio/amrwb"); ++ ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingAMR; ++ ++ addPort(def); ++ ++ def.nPortIndex = 1; ++ def.eDir = OMX_DirOutput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ ++ def.nBufferSize = ++ (mMode == MODE_NARROW ? kNumSamplesPerFrameNB : kNumSamplesPerFrameWB) ++ * sizeof(int16_t); ++ ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 2; ++ ++ def.format.audio.cMIMEType = const_cast("audio/raw"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; ++ ++ addPort(def); ++} ++ ++status_t SoftAMR::initDecoder() { ++ if (mMode == MODE_NARROW) { ++ Word16 err = GSMInitDecode(&mState, (Word8 *)"AMRNBDecoder"); ++ ++ if (err != 0) { ++ return UNKNOWN_ERROR; ++ } ++ } else { ++ int32_t memReq = pvDecoder_AmrWbMemRequirements(); ++ mDecoderBuf = malloc(memReq); ++ ++ pvDecoder_AmrWb_Init(&mState, mDecoderBuf, &mDecoderCookie); ++ } ++ ++ return OK; ++} ++ ++OMX_ERRORTYPE SoftAMR::internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamAudioPortFormat: ++ { ++ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (formatParams->nIndex > 0) { ++ return OMX_ErrorNoMore; ++ } ++ ++ formatParams->eEncoding = ++ (formatParams->nPortIndex == 0) ++ ? OMX_AUDIO_CodingAMR : OMX_AUDIO_CodingPCM; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioAmr: ++ { ++ OMX_AUDIO_PARAM_AMRTYPE *amrParams = ++ (OMX_AUDIO_PARAM_AMRTYPE *)params; ++ ++ if (!isValidOMXParam(amrParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (amrParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ amrParams->nChannels = 1; ++ amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff; ++ amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; ++ ++ if (!isConfigured()) { ++ amrParams->nBitRate = 0; ++ amrParams->eAMRBandMode = OMX_AUDIO_AMRBandModeUnused; ++ } else { ++ amrParams->nBitRate = 0; ++ amrParams->eAMRBandMode = ++ mMode == MODE_NARROW ++ ? OMX_AUDIO_AMRBandModeNB0 : OMX_AUDIO_AMRBandModeWB0; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ pcmParams->nChannels = 1; ++ pcmParams->eNumData = OMX_NumericalDataSigned; ++ pcmParams->eEndian = OMX_EndianBig; ++ pcmParams->bInterleaved = OMX_TRUE; ++ pcmParams->nBitPerSample = 16; ++ ++ pcmParams->nSamplingRate = ++ (mMode == MODE_NARROW) ? kSampleRateNB : kSampleRateWB; ++ ++ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; ++ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; ++ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalGetParameter(index, params); ++ } ++} ++ ++OMX_ERRORTYPE SoftAMR::internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamStandardComponentRole: ++ { ++ const OMX_PARAM_COMPONENTROLETYPE *roleParams = ++ (const OMX_PARAM_COMPONENTROLETYPE *)params; ++ ++ if (!isValidOMXParam(roleParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (mMode == MODE_NARROW) { ++ if (strncmp((const char *)roleParams->cRole, ++ "audio_decoder.amrnb", ++ OMX_MAX_STRINGNAME_SIZE - 1)) { ++ return OMX_ErrorUndefined; ++ } ++ } else { ++ if (strncmp((const char *)roleParams->cRole, ++ "audio_decoder.amrwb", ++ OMX_MAX_STRINGNAME_SIZE - 1)) { ++ return OMX_ErrorUndefined; ++ } ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPortFormat: ++ { ++ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if ((formatParams->nPortIndex == 0 ++ && formatParams->eEncoding != OMX_AUDIO_CodingAMR) ++ || (formatParams->nPortIndex == 1 ++ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioAmr: ++ { ++ const OMX_AUDIO_PARAM_AMRTYPE *aacParams = ++ (const OMX_AUDIO_PARAM_AMRTYPE *)params; ++ ++ if (!isValidOMXParam(aacParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (aacParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalSetParameter(index, params); ++ } ++} ++ ++bool SoftAMR::isConfigured() const { ++ return mInputBufferCount > 0; ++} ++ ++static size_t getFrameSize(unsigned FT) { ++ static const size_t kFrameSizeWB[10] = { ++ 132, 177, 253, 285, 317, 365, 397, 461, 477, 40 ++ }; ++ ++ if (FT >= 10) { ++ return 1; ++ } ++ ++ size_t frameSize = kFrameSizeWB[FT]; ++ ++ // Round up bits to bytes and add 1 for the header byte. ++ frameSize = (frameSize + 7) / 8 + 1; ++ ++ return frameSize; ++} ++ ++void SoftAMR::onQueueFilled(OMX_U32 /* portIndex */) { ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ ++ if (mSignalledError || mOutputPortSettingsChange != NONE) { ++ return; ++ } ++ ++ while (!inQueue.empty() && !outQueue.empty()) { ++ BufferInfo *inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++ ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ ++ if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) { ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ ++ outHeader->nFilledLen = 0; ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ ++ outQueue.erase(outQueue.begin()); ++ outInfo->mOwnedByUs = false; ++ notifyFillBufferDone(outHeader); ++ return; ++ } ++ ++ if (inHeader->nFilledLen == 0) { ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ notifyEmptyBufferDone(inHeader); ++ continue; ++ } ++ ++ if (inHeader->nOffset == 0) { ++ mAnchorTimeUs = inHeader->nTimeStamp; ++ mNumSamplesOutput = 0; ++ } ++ ++ const uint8_t *inputPtr = inHeader->pBuffer + inHeader->nOffset; ++ int32_t numBytesRead; ++ ++ if (mMode == MODE_NARROW) { ++ if (outHeader->nAllocLen < kNumSamplesPerFrameNB * sizeof(int16_t)) { ++ ALOGE("b/27662364: NB expected output buffer %zu bytes vs %u", ++ kNumSamplesPerFrameNB * sizeof(int16_t), outHeader->nAllocLen); ++ android_errorWriteLog(0x534e4554, "27662364"); ++ notify(OMX_EventError, OMX_ErrorOverflow, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ int16 mode = ((inputPtr[0] >> 3) & 0x0f); ++ // for WMF since MIME_IETF is used when calling AMRDecode. ++ size_t frameSize = WmfDecBytesPerFrame[mode] + 1; ++ ++ if (inHeader->nFilledLen < frameSize) { ++ ALOGE("b/27662364: expected %zu bytes vs %u", frameSize, inHeader->nFilledLen); ++ notify(OMX_EventError, OMX_ErrorStreamCorrupt, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ numBytesRead = ++ AMRDecode(mState, ++ (Frame_Type_3GPP)((inputPtr[0] >> 3) & 0x0f), ++ (UWord8 *)&inputPtr[1], ++ reinterpret_cast(outHeader->pBuffer), ++ MIME_IETF); ++ ++ if (numBytesRead == -1) { ++ ALOGE("PV AMR decoder AMRDecode() call failed"); ++ ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ ++ return; ++ } ++ ++ ++numBytesRead; // Include the frame type header byte. ++ ++ if (static_cast(numBytesRead) > inHeader->nFilledLen) { ++ // This is bad, should never have happened, but did. Abort now. ++ ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ ++ return; ++ } ++ } else { ++ if (outHeader->nAllocLen < kNumSamplesPerFrameWB * sizeof(int16_t)) { ++ ALOGE("b/27662364: WB expected output buffer %zu bytes vs %u", ++ kNumSamplesPerFrameWB * sizeof(int16_t), outHeader->nAllocLen); ++ android_errorWriteLog(0x534e4554, "27662364"); ++ notify(OMX_EventError, OMX_ErrorOverflow, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ int16 mode = ((inputPtr[0] >> 3) & 0x0f); ++ ++ if (mode >= 10 && mode <= 13) { ++ ALOGE("encountered illegal frame type %d in AMR WB content.", ++ mode); ++ ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ ++ return; ++ } ++ ++ size_t frameSize = getFrameSize(mode); ++ if (inHeader->nFilledLen < frameSize) { ++ ALOGE("b/27662364: expected %zu bytes vs %u", frameSize, inHeader->nFilledLen); ++ notify(OMX_EventError, OMX_ErrorStreamCorrupt, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ int16_t *outPtr = (int16_t *)outHeader->pBuffer; ++ ++ if (mode >= 9) { ++ // Produce silence instead of comfort noise and for ++ // speech lost/no data. ++ memset(outPtr, 0, kNumSamplesPerFrameWB * sizeof(int16_t)); ++ } else if (mode < 9) { ++ int16 frameType; ++ mime_unsorting( ++ const_cast(&inputPtr[1]), ++ mInputSampleBuffer, ++ &frameType, &mode, 1, &mRxState); ++ ++ int16_t numSamplesOutput; ++ pvDecoder_AmrWb( ++ mode, mInputSampleBuffer, ++ outPtr, ++ &numSamplesOutput, ++ mDecoderBuf, frameType, mDecoderCookie); ++ ++ CHECK_EQ((int)numSamplesOutput, (int)kNumSamplesPerFrameWB); ++ ++ for (int i = 0; i < kNumSamplesPerFrameWB; ++i) { ++ /* Delete the 2 LSBs (14-bit output) */ ++ outPtr[i] &= 0xfffC; ++ } ++ } ++ ++ numBytesRead = frameSize; ++ } ++ ++ inHeader->nOffset += numBytesRead; ++ inHeader->nFilledLen -= numBytesRead; ++ ++ outHeader->nFlags = 0; ++ outHeader->nOffset = 0; ++ ++ if (mMode == MODE_NARROW) { ++ outHeader->nFilledLen = kNumSamplesPerFrameNB * sizeof(int16_t); ++ ++ outHeader->nTimeStamp = ++ mAnchorTimeUs ++ + (mNumSamplesOutput * 1000000LL) / kSampleRateNB; ++ ++ mNumSamplesOutput += kNumSamplesPerFrameNB; ++ } else { ++ outHeader->nFilledLen = kNumSamplesPerFrameWB * sizeof(int16_t); ++ ++ outHeader->nTimeStamp = ++ mAnchorTimeUs ++ + (mNumSamplesOutput * 1000000LL) / kSampleRateWB; ++ ++ mNumSamplesOutput += kNumSamplesPerFrameWB; ++ } ++ ++ if (inHeader->nFilledLen == 0 && (inHeader->nFlags & OMX_BUFFERFLAG_EOS) == 0) { ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ } ++ ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ outInfo = NULL; ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ ++ ++mInputBufferCount; ++ } ++} ++ ++void SoftAMR::onPortFlushCompleted(OMX_U32 portIndex) { ++ ALOGV("onPortFlushCompleted portindex %d, resetting frame ", portIndex); ++ if (portIndex == 0) { ++ if (mMode == MODE_NARROW) { ++ Speech_Decode_Frame_reset(mState); ++ } else { ++ pvDecoder_AmrWb_Reset(mState, 0 /* reset_all */); ++ } ++ } ++} ++ ++void SoftAMR::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { ++ if (portIndex != 1) { ++ return; ++ } ++ ++ switch (mOutputPortSettingsChange) { ++ case NONE: ++ break; ++ ++ case AWAITING_DISABLED: ++ { ++ CHECK(!enabled); ++ mOutputPortSettingsChange = AWAITING_ENABLED; ++ break; ++ } ++ ++ default: ++ { ++ CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); ++ CHECK(enabled); ++ mOutputPortSettingsChange = NONE; ++ break; ++ } ++ } ++} ++ ++void SoftAMR::onReset() { ++ mSignalledError = false; ++ mOutputPortSettingsChange = NONE; ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ return new android::SoftAMR(name, callbacks, appData, component); ++} ++ +diff --git a/media/libstagefright/codecs/amrnb/dec/SoftAMR.h b/media/libstagefright/codecs/amrnb/dec/SoftAMR.h +new file mode 100644 +index 0000000..d5aaed3 +--- /dev/null ++++ b/media/libstagefright/codecs/amrnb/dec/SoftAMR.h +@@ -0,0 +1,91 @@ ++/* ++ * Copyright (C) 2011 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 SOFT_AMR_H_ ++ ++#define SOFT_AMR_H_ ++ ++#include ++#include "gsmamr_dec.h" ++#include "pvamrwbdecoder.h" ++ ++namespace android { ++ ++struct SoftAMR : public SimpleSoftOMXComponent { ++ SoftAMR(const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++protected: ++ virtual ~SoftAMR(); ++ ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params); ++ ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ virtual void onPortFlushCompleted(OMX_U32 portIndex); ++ virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled); ++ virtual void onReset(); ++ ++private: ++ enum { ++ kNumBuffers = 4, ++ kSampleRateNB = 8000, ++ kSampleRateWB = 16000, ++ kNumSamplesPerFrameNB = 160, ++ kNumSamplesPerFrameWB = 320, ++ }; ++ ++ enum { ++ MODE_NARROW, ++ MODE_WIDE ++ ++ } mMode; ++ ++ void *mState; ++ void *mDecoderBuf; ++ int16_t *mDecoderCookie; ++ RX_State_wb mRxState{}; ++ ++ size_t mInputBufferCount; ++ int64_t mAnchorTimeUs; ++ int64_t mNumSamplesOutput; ++ ++ bool mSignalledError; ++ ++ enum { ++ NONE, ++ AWAITING_DISABLED, ++ AWAITING_ENABLED ++ } mOutputPortSettingsChange; ++ ++ int16_t mInputSampleBuffer[477]; ++ ++ void initPorts(); ++ status_t initDecoder(); ++ bool isConfigured() const; ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftAMR); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_AMR_H_ ++ +diff --git a/media/libstagefright/codecs/amrnb/dec/exports.lds b/media/libstagefright/codecs/amrnb/dec/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/amrnb/dec/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/amrnb/enc/Android.bp b/media/libstagefright/codecs/amrnb/enc/Android.bp +new file mode 100644 +index 0000000..6bf2d39 +--- /dev/null ++++ b/media/libstagefright/codecs/amrnb/enc/Android.bp +@@ -0,0 +1,31 @@ ++ ++//############################################################################### ++ ++package { ++ // See: http://go/android-license-faq ++ // A large-scale-change added 'default_applicable_licenses' to import ++ // all of the 'license_kinds' from "frameworks_av_media_libstagefright_license" ++ // to get the below license kinds: ++ // SPDX-license-identifier-Apache-2.0 ++ default_applicable_licenses: ["frameworks_av_media_libstagefright_license"], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_amrnbenc", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: ["SoftAMRNBEncoder.cpp"], ++ ++ //addressing b/25409744 ++ //sanitize: { ++ // misc_undefined: [ ++ // "signed-integer-overflow", ++ // ], ++ //}, ++ ++ static_libs: ["libstagefright_amrnbenc"], ++ ++ shared_libs: [ ++ "libstagefright_amrnb_common", ++ ], ++} +diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp +new file mode 100644 +index 0000000..a1f6686 +--- /dev/null ++++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp +@@ -0,0 +1,429 @@ ++/* ++ * Copyright (C) 2012 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 "SoftAMRNBEncoder" ++#include ++ ++#include "SoftAMRNBEncoder.h" ++ ++#include "gsmamr_enc.h" ++ ++#include ++#include ++ ++namespace android { ++ ++static const int32_t kSampleRate = 8000; ++ ++template ++static void InitOMXParams(T *params) { ++ params->nSize = sizeof(T); ++ params->nVersion.s.nVersionMajor = 1; ++ params->nVersion.s.nVersionMinor = 0; ++ params->nVersion.s.nRevision = 0; ++ params->nVersion.s.nStep = 0; ++} ++ ++SoftAMRNBEncoder::SoftAMRNBEncoder( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SimpleSoftOMXComponent(name, callbacks, appData, component), ++ mEncState(NULL), ++ mSidState(NULL), ++ mBitRate(0), ++ mMode(MR475), ++ mInputSize(0), ++ mInputTimeUs(-1LL), ++ mSawInputEOS(false), ++ mSignalledError(false) { ++ initPorts(); ++ CHECK_EQ(initEncoder(), (status_t)OK); ++} ++ ++SoftAMRNBEncoder::~SoftAMRNBEncoder() { ++ if (mEncState != NULL) { ++ AMREncodeExit(&mEncState, &mSidState); ++ mEncState = mSidState = NULL; ++ } ++} ++ ++void SoftAMRNBEncoder::initPorts() { ++ OMX_PARAM_PORTDEFINITIONTYPE def; ++ InitOMXParams(&def); ++ ++ def.nPortIndex = 0; ++ def.eDir = OMX_DirInput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t); ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 1; ++ ++ def.format.audio.cMIMEType = const_cast("audio/raw"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; ++ ++ addPort(def); ++ ++ def.nPortIndex = 1; ++ def.eDir = OMX_DirOutput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = 8192; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 2; ++ ++ def.format.audio.cMIMEType = const_cast("audio/3gpp"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingAMR; ++ ++ addPort(def); ++} ++ ++status_t SoftAMRNBEncoder::initEncoder() { ++ if (AMREncodeInit(&mEncState, &mSidState, false /* dtx_enable */) != 0) { ++ return UNKNOWN_ERROR; ++ } ++ ++ return OK; ++} ++ ++OMX_ERRORTYPE SoftAMRNBEncoder::internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamAudioPortFormat: ++ { ++ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (formatParams->nIndex > 0) { ++ return OMX_ErrorNoMore; ++ } ++ ++ formatParams->eEncoding = ++ (formatParams->nPortIndex == 0) ++ ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAMR; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioAmr: ++ { ++ OMX_AUDIO_PARAM_AMRTYPE *amrParams = ++ (OMX_AUDIO_PARAM_AMRTYPE *)params; ++ ++ if (!isValidOMXParam(amrParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (amrParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ amrParams->nChannels = 1; ++ amrParams->nBitRate = mBitRate; ++ amrParams->eAMRBandMode = (OMX_AUDIO_AMRBANDMODETYPE)(mMode + 1); ++ amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff; ++ amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ pcmParams->eNumData = OMX_NumericalDataSigned; ++ pcmParams->eEndian = OMX_EndianBig; ++ pcmParams->bInterleaved = OMX_TRUE; ++ pcmParams->nBitPerSample = 16; ++ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; ++ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelCF; ++ ++ pcmParams->nChannels = 1; ++ pcmParams->nSamplingRate = kSampleRate; ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalGetParameter(index, params); ++ } ++} ++ ++OMX_ERRORTYPE SoftAMRNBEncoder::internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamStandardComponentRole: ++ { ++ const OMX_PARAM_COMPONENTROLETYPE *roleParams = ++ (const OMX_PARAM_COMPONENTROLETYPE *)params; ++ ++ if (!isValidOMXParam(roleParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (strncmp((const char *)roleParams->cRole, ++ "audio_encoder.amrnb", ++ OMX_MAX_STRINGNAME_SIZE - 1)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPortFormat: ++ { ++ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if ((formatParams->nPortIndex == 0 ++ && formatParams->eEncoding != OMX_AUDIO_CodingPCM) ++ || (formatParams->nPortIndex == 1 ++ && formatParams->eEncoding != OMX_AUDIO_CodingAMR)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioAmr: ++ { ++ OMX_AUDIO_PARAM_AMRTYPE *amrParams = ++ (OMX_AUDIO_PARAM_AMRTYPE *)params; ++ ++ if (!isValidOMXParam(amrParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (amrParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (amrParams->nChannels != 1 ++ || amrParams->eAMRDTXMode != OMX_AUDIO_AMRDTXModeOff ++ || amrParams->eAMRFrameFormat ++ != OMX_AUDIO_AMRFrameFormatFSF ++ || amrParams->eAMRBandMode < OMX_AUDIO_AMRBandModeNB0 ++ || amrParams->eAMRBandMode > OMX_AUDIO_AMRBandModeNB7) { ++ return OMX_ErrorUndefined; ++ } ++ ++ mBitRate = amrParams->nBitRate; ++ mMode = amrParams->eAMRBandMode - 1; ++ ++ amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff; ++ amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (pcmParams->nChannels != 1 ++ || pcmParams->nSamplingRate != (OMX_U32)kSampleRate) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ ++ default: ++ return SimpleSoftOMXComponent::internalSetParameter(index, params); ++ } ++} ++ ++void SoftAMRNBEncoder::onQueueFilled(OMX_U32 /* portIndex */) { ++ if (mSignalledError) { ++ return; ++ } ++ ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ ++ size_t numBytesPerInputFrame = kNumSamplesPerFrame * sizeof(int16_t); ++ ++ for (;;) { ++ // We do the following until we run out of buffers. ++ ++ while (mInputSize < numBytesPerInputFrame) { ++ // As long as there's still input data to be read we ++ // will drain "kNumSamplesPerFrame" samples ++ // into the "mInputFrame" buffer and then encode those ++ // as a unit into an output buffer. ++ ++ if (mSawInputEOS || inQueue.empty()) { ++ return; ++ } ++ ++ BufferInfo *inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++ ++ const void *inData = inHeader->pBuffer + inHeader->nOffset; ++ ++ size_t copy = numBytesPerInputFrame - mInputSize; ++ if (copy > inHeader->nFilledLen) { ++ copy = inHeader->nFilledLen; ++ } ++ ++ if (mInputSize == 0) { ++ mInputTimeUs = inHeader->nTimeStamp; ++ } ++ ++ memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy); ++ mInputSize += copy; ++ ++ inHeader->nOffset += copy; ++ inHeader->nFilledLen -= copy; ++ ++ // "Time" on the input buffer has in effect advanced by the ++ // number of audio frames we just advanced nOffset by. ++ inHeader->nTimeStamp += ++ (copy * 1000000LL / kSampleRate) / sizeof(int16_t); ++ ++ if (inHeader->nFilledLen == 0) { ++ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ ALOGV("saw input EOS"); ++ mSawInputEOS = true; ++ ++ // Pad any remaining data with zeroes. ++ memset((uint8_t *)mInputFrame + mInputSize, ++ 0, ++ numBytesPerInputFrame - mInputSize); ++ ++ mInputSize = numBytesPerInputFrame; ++ } ++ ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ ++ inData = NULL; ++ inHeader = NULL; ++ inInfo = NULL; ++ } ++ } ++ ++ // At this point we have all the input data necessary to encode ++ // a single frame, all we need is an output buffer to store the result ++ // in. ++ ++ if (outQueue.empty()) { ++ return; ++ } ++ ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ ++ uint8_t *outPtr = outHeader->pBuffer + outHeader->nOffset; ++ size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset; ++ ++ Frame_Type_3GPP frameType; ++ int res = AMREncode( ++ mEncState, mSidState, (Mode)mMode, ++ mInputFrame, outPtr, &frameType, AMR_TX_WMF); ++ ++ CHECK_GE(res, 0); ++ CHECK_LE((size_t)res, outAvailable); ++ ++ // Convert header byte from WMF to IETF format. ++ outPtr[0] = ((outPtr[0] << 3) | 4) & 0x7c; ++ ++ outHeader->nFilledLen = res; ++ outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME; ++ ++ if (mSawInputEOS) { ++ // We also tag this output buffer with EOS if it corresponds ++ // to the final input buffer. ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ } ++ ++ outHeader->nTimeStamp = mInputTimeUs; ++ ++#if 0 ++ ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)", ++ nOutputBytes, mInputTimeUs, outHeader->nFlags); ++ ++ hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen); ++#endif ++ ++ outQueue.erase(outQueue.begin()); ++ outInfo->mOwnedByUs = false; ++ notifyFillBufferDone(outHeader); ++ ++ outHeader = NULL; ++ outInfo = NULL; ++ ++ mInputSize = 0; ++ } ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ return new android::SoftAMRNBEncoder(name, callbacks, appData, component); ++} +diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h +new file mode 100644 +index 0000000..c73e4dd +--- /dev/null ++++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h +@@ -0,0 +1,72 @@ ++/* ++ * Copyright (C) 2012 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 SOFT_AMRNB_ENCODER_H_ ++ ++#define SOFT_AMRNB_ENCODER_H_ ++ ++#include ++ ++namespace android { ++ ++struct SoftAMRNBEncoder : public SimpleSoftOMXComponent { ++ SoftAMRNBEncoder( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++protected: ++ virtual ~SoftAMRNBEncoder(); ++ ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params); ++ ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ ++private: ++ enum { ++ kNumBuffers = 4, ++ kNumSamplesPerFrame = 160, ++ }; ++ ++ void *mEncState; ++ void *mSidState; ++ ++ OMX_U32 mBitRate; ++ int mMode; ++ ++ size_t mInputSize; ++ int16_t mInputFrame[kNumSamplesPerFrame]; ++ int64_t mInputTimeUs; ++ ++ bool mSawInputEOS; ++ bool mSignalledError; ++ ++ void initPorts(); ++ status_t initEncoder(); ++ ++ status_t setAudioParams(); ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftAMRNBEncoder); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_AMRNB_ENCODER_H_ +diff --git a/media/libstagefright/codecs/amrnb/enc/exports.lds b/media/libstagefright/codecs/amrnb/enc/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/amrnb/enc/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/amrwbenc/Android.bp b/media/libstagefright/codecs/amrwbenc/Android.bp +new file mode 100644 +index 0000000..00e7bc9 +--- /dev/null ++++ b/media/libstagefright/codecs/amrwbenc/Android.bp +@@ -0,0 +1,31 @@ ++ ++package { ++ // See: http://go/android-license-faq ++ // A large-scale-change added 'default_applicable_licenses' to import ++ // all of the 'license_kinds' from "frameworks_av_media_libstagefright_license" ++ // to get the below license kinds: ++ // SPDX-license-identifier-Apache-2.0 ++ default_applicable_licenses: ["frameworks_av_media_libstagefright_license"], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_amrwbenc", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: ["SoftAMRWBEncoder.cpp"], ++ ++ version_script: "exports.lds", ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ ], ++ cfi: true, ++ }, ++ ++ static_libs: ["libstagefright_amrwbenc"], ++ ++ shared_libs: [ ++ "libstagefright_enc_common", ++ ], ++} +diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp +new file mode 100644 +index 0000000..657a5ce +--- /dev/null ++++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp +@@ -0,0 +1,484 @@ ++/* ++ * Copyright (C) 2012 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 "SoftAMRWBEncoder" ++#include ++ ++#include "SoftAMRWBEncoder.h" ++ ++#include "cmnMemory.h" ++ ++#include ++#include ++ ++namespace android { ++ ++static const int32_t kSampleRate = 16000; ++ ++template ++static void InitOMXParams(T *params) { ++ params->nSize = sizeof(T); ++ params->nVersion.s.nVersionMajor = 1; ++ params->nVersion.s.nVersionMinor = 0; ++ params->nVersion.s.nRevision = 0; ++ params->nVersion.s.nStep = 0; ++} ++ ++SoftAMRWBEncoder::SoftAMRWBEncoder( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SimpleSoftOMXComponent(name, callbacks, appData, component), ++ mEncoderHandle(NULL), ++ mApiHandle(NULL), ++ mMemOperator(NULL), ++ mBitRate(0), ++ mMode(VOAMRWB_MD66), ++ mInputSize(0), ++ mInputTimeUs(-1LL), ++ mSawInputEOS(false), ++ mSignalledError(false) { ++ initPorts(); ++ CHECK_EQ(initEncoder(), (status_t)OK); ++} ++ ++SoftAMRWBEncoder::~SoftAMRWBEncoder() { ++ if (mEncoderHandle != NULL) { ++ CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle)); ++ mEncoderHandle = NULL; ++ } ++ ++ delete mApiHandle; ++ mApiHandle = NULL; ++ ++ delete mMemOperator; ++ mMemOperator = NULL; ++} ++ ++void SoftAMRWBEncoder::initPorts() { ++ OMX_PARAM_PORTDEFINITIONTYPE def; ++ InitOMXParams(&def); ++ ++ def.nPortIndex = 0; ++ def.eDir = OMX_DirInput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t); ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 1; ++ ++ def.format.audio.cMIMEType = const_cast("audio/raw"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; ++ ++ addPort(def); ++ ++ def.nPortIndex = 1; ++ def.eDir = OMX_DirOutput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = 8192; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 2; ++ ++ def.format.audio.cMIMEType = const_cast("audio/amr-wb"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingAMR; ++ ++ addPort(def); ++} ++ ++status_t SoftAMRWBEncoder::initEncoder() { ++ mApiHandle = new VO_AUDIO_CODECAPI; ++ ++ if (VO_ERR_NONE != voGetAMRWBEncAPI(mApiHandle)) { ++ ALOGE("Failed to get api handle"); ++ return UNKNOWN_ERROR; ++ } ++ ++ mMemOperator = new VO_MEM_OPERATOR; ++ mMemOperator->Alloc = cmnMemAlloc; ++ mMemOperator->Copy = cmnMemCopy; ++ mMemOperator->Free = cmnMemFree; ++ mMemOperator->Set = cmnMemSet; ++ mMemOperator->Check = cmnMemCheck; ++ ++ VO_CODEC_INIT_USERDATA userData; ++ memset(&userData, 0, sizeof(userData)); ++ userData.memflag = VO_IMF_USERMEMOPERATOR; ++ userData.memData = (VO_PTR) mMemOperator; ++ ++ if (VO_ERR_NONE != mApiHandle->Init( ++ &mEncoderHandle, VO_AUDIO_CodingAMRWB, &userData)) { ++ ALOGE("Failed to init AMRWB encoder"); ++ return UNKNOWN_ERROR; ++ } ++ ++ VOAMRWBFRAMETYPE type = VOAMRWB_RFC3267; ++ if (VO_ERR_NONE != mApiHandle->SetParam( ++ mEncoderHandle, VO_PID_AMRWB_FRAMETYPE, &type)) { ++ ALOGE("Failed to set AMRWB encoder frame type to %d", type); ++ return UNKNOWN_ERROR; ++ } ++ ++ return OK; ++} ++ ++OMX_ERRORTYPE SoftAMRWBEncoder::internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamAudioPortFormat: ++ { ++ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (formatParams->nIndex > 0) { ++ return OMX_ErrorNoMore; ++ } ++ ++ formatParams->eEncoding = ++ (formatParams->nPortIndex == 0) ++ ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAMR; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioAmr: ++ { ++ OMX_AUDIO_PARAM_AMRTYPE *amrParams = ++ (OMX_AUDIO_PARAM_AMRTYPE *)params; ++ ++ if (!isValidOMXParam(amrParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (amrParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ amrParams->nChannels = 1; ++ amrParams->nBitRate = mBitRate; ++ ++ amrParams->eAMRBandMode = ++ (OMX_AUDIO_AMRBANDMODETYPE)(mMode + OMX_AUDIO_AMRBandModeWB0); ++ ++ amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff; ++ amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ pcmParams->eNumData = OMX_NumericalDataSigned; ++ pcmParams->eEndian = OMX_EndianBig; ++ pcmParams->bInterleaved = OMX_TRUE; ++ pcmParams->nBitPerSample = 16; ++ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; ++ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelCF; ++ ++ pcmParams->nChannels = 1; ++ pcmParams->nSamplingRate = kSampleRate; ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalGetParameter(index, params); ++ } ++} ++ ++OMX_ERRORTYPE SoftAMRWBEncoder::internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamStandardComponentRole: ++ { ++ const OMX_PARAM_COMPONENTROLETYPE *roleParams = ++ (const OMX_PARAM_COMPONENTROLETYPE *)params; ++ ++ if (!isValidOMXParam(roleParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (strncmp((const char *)roleParams->cRole, ++ "audio_encoder.amrwb", ++ OMX_MAX_STRINGNAME_SIZE - 1)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPortFormat: ++ { ++ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if ((formatParams->nPortIndex == 0 ++ && formatParams->eEncoding != OMX_AUDIO_CodingPCM) ++ || (formatParams->nPortIndex == 1 ++ && formatParams->eEncoding != OMX_AUDIO_CodingAMR)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioAmr: ++ { ++ OMX_AUDIO_PARAM_AMRTYPE *amrParams = ++ (OMX_AUDIO_PARAM_AMRTYPE *)params; ++ ++ if (!isValidOMXParam(amrParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (amrParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (amrParams->nChannels != 1 ++ || amrParams->eAMRDTXMode != OMX_AUDIO_AMRDTXModeOff ++ || amrParams->eAMRFrameFormat ++ != OMX_AUDIO_AMRFrameFormatFSF ++ || amrParams->eAMRBandMode < OMX_AUDIO_AMRBandModeWB0 ++ || amrParams->eAMRBandMode > OMX_AUDIO_AMRBandModeWB8) { ++ return OMX_ErrorUndefined; ++ } ++ ++ mBitRate = amrParams->nBitRate; ++ ++ mMode = (VOAMRWBMODE)( ++ amrParams->eAMRBandMode - OMX_AUDIO_AMRBandModeWB0); ++ ++ amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff; ++ amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; ++ ++ if (VO_ERR_NONE != ++ mApiHandle->SetParam( ++ mEncoderHandle, VO_PID_AMRWB_MODE, &mMode)) { ++ ALOGE("Failed to set AMRWB encoder mode to %d", mMode); ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (pcmParams->nChannels != 1 ++ || pcmParams->nSamplingRate != (OMX_U32)kSampleRate) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ ++ default: ++ return SimpleSoftOMXComponent::internalSetParameter(index, params); ++ } ++} ++ ++void SoftAMRWBEncoder::onQueueFilled(OMX_U32 /* portIndex */) { ++ if (mSignalledError) { ++ return; ++ } ++ ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ ++ size_t numBytesPerInputFrame = kNumSamplesPerFrame * sizeof(int16_t); ++ ++ for (;;) { ++ // We do the following until we run out of buffers. ++ ++ while (mInputSize < numBytesPerInputFrame) { ++ // As long as there's still input data to be read we ++ // will drain "kNumSamplesPerFrame" samples ++ // into the "mInputFrame" buffer and then encode those ++ // as a unit into an output buffer. ++ ++ if (mSawInputEOS || inQueue.empty()) { ++ return; ++ } ++ ++ BufferInfo *inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++ ++ const void *inData = inHeader->pBuffer + inHeader->nOffset; ++ ++ size_t copy = numBytesPerInputFrame - mInputSize; ++ if (copy > inHeader->nFilledLen) { ++ copy = inHeader->nFilledLen; ++ } ++ ++ if (mInputSize == 0) { ++ mInputTimeUs = inHeader->nTimeStamp; ++ } ++ ++ memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy); ++ mInputSize += copy; ++ ++ inHeader->nOffset += copy; ++ inHeader->nFilledLen -= copy; ++ ++ // "Time" on the input buffer has in effect advanced by the ++ // number of audio frames we just advanced nOffset by. ++ inHeader->nTimeStamp += ++ (copy * 1000000LL / kSampleRate) / sizeof(int16_t); ++ ++ if (inHeader->nFilledLen == 0) { ++ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ ALOGV("saw input EOS"); ++ mSawInputEOS = true; ++ ++ // Pad any remaining data with zeroes. ++ memset((uint8_t *)mInputFrame + mInputSize, ++ 0, ++ numBytesPerInputFrame - mInputSize); ++ ++ mInputSize = numBytesPerInputFrame; ++ } ++ ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ ++ inData = NULL; ++ inHeader = NULL; ++ inInfo = NULL; ++ } ++ } ++ ++ // At this point we have all the input data necessary to encode ++ // a single frame, all we need is an output buffer to store the result ++ // in. ++ ++ if (outQueue.empty()) { ++ return; ++ } ++ ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ ++ uint8_t *outPtr = outHeader->pBuffer + outHeader->nOffset; ++ size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset; ++ ++ VO_CODECBUFFER inputData; ++ memset(&inputData, 0, sizeof(inputData)); ++ inputData.Buffer = (unsigned char *) mInputFrame; ++ inputData.Length = mInputSize; ++ ++ CHECK_EQ((VO_U32)VO_ERR_NONE, ++ mApiHandle->SetInputData(mEncoderHandle, &inputData)); ++ ++ VO_CODECBUFFER outputData; ++ memset(&outputData, 0, sizeof(outputData)); ++ VO_AUDIO_OUTPUTINFO outputInfo; ++ memset(&outputInfo, 0, sizeof(outputInfo)); ++ ++ outputData.Buffer = outPtr; ++ outputData.Length = outAvailable; ++ VO_U32 ret = mApiHandle->GetOutputData( ++ mEncoderHandle, &outputData, &outputInfo); ++ CHECK(ret == VO_ERR_NONE || ret == VO_ERR_INPUT_BUFFER_SMALL); ++ ++ outHeader->nFilledLen = outputData.Length; ++ outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME; ++ ++ if (mSawInputEOS) { ++ // We also tag this output buffer with EOS if it corresponds ++ // to the final input buffer. ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ } ++ ++ outHeader->nTimeStamp = mInputTimeUs; ++ ++#if 0 ++ ALOGI("sending %ld bytes of data (time = %lld us, flags = 0x%08lx)", ++ outHeader->nFilledLen, mInputTimeUs, outHeader->nFlags); ++ ++ hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen); ++#endif ++ ++ outQueue.erase(outQueue.begin()); ++ outInfo->mOwnedByUs = false; ++ notifyFillBufferDone(outHeader); ++ ++ outHeader = NULL; ++ outInfo = NULL; ++ ++ mInputSize = 0; ++ } ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ return new android::SoftAMRWBEncoder(name, callbacks, appData, component); ++} +diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h +new file mode 100644 +index 0000000..8950a8c +--- /dev/null ++++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h +@@ -0,0 +1,76 @@ ++/* ++ * Copyright (C) 2012 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 SOFT_AMRWB_ENCODER_H_ ++ ++#define SOFT_AMRWB_ENCODER_H_ ++ ++#include ++ ++#include "voAMRWB.h" ++ ++struct VO_AUDIO_CODECAPI; ++struct VO_MEM_OPERATOR; ++ ++namespace android { ++ ++struct SoftAMRWBEncoder : public SimpleSoftOMXComponent { ++ SoftAMRWBEncoder( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++protected: ++ virtual ~SoftAMRWBEncoder(); ++ ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params); ++ ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ ++private: ++ enum { ++ kNumBuffers = 4, ++ kNumSamplesPerFrame = 320, ++ }; ++ ++ void *mEncoderHandle; ++ VO_AUDIO_CODECAPI *mApiHandle; ++ VO_MEM_OPERATOR *mMemOperator; ++ ++ OMX_U32 mBitRate; ++ VOAMRWBMODE mMode; ++ ++ size_t mInputSize; ++ int16_t mInputFrame[kNumSamplesPerFrame]; ++ int64_t mInputTimeUs; ++ ++ bool mSawInputEOS; ++ bool mSignalledError; ++ ++ void initPorts(); ++ status_t initEncoder(); ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftAMRWBEncoder); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_AMRWB_ENCODER_H_ +diff --git a/media/libstagefright/codecs/amrwbenc/exports.lds b/media/libstagefright/codecs/amrwbenc/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/amrwbenc/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/avcdec/Android.bp b/media/libstagefright/codecs/avcdec/Android.bp +new file mode 100644 +index 0000000..1c2f9be +--- /dev/null ++++ b/media/libstagefright/codecs/avcdec/Android.bp +@@ -0,0 +1,34 @@ ++package { ++ // See: http://go/android-license-faq ++ // A large-scale-change added 'default_applicable_licenses' to import ++ // all of the 'license_kinds' from "frameworks_av_media_libstagefright_license" ++ // to get the below license kinds: ++ // SPDX-license-identifier-Apache-2.0 ++ default_applicable_licenses: ["frameworks_av_media_libstagefright_license"], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_avcdec", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ static_libs: ["libavcdec"], ++ srcs: ["SoftAVCDec.cpp"], ++ ++ cflags: [ ++ "-Wall", ++ ], ++ ++ version_script: "exports.lds", ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ ], ++ cfi: true, ++ config: { ++ cfi_assembly_support: true, ++ }, ++ }, ++ ++ ldflags: ["-Wl,-Bsymbolic"], ++} +diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp +new file mode 100644 +index 0000000..3891f23 +--- /dev/null ++++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp +@@ -0,0 +1,732 @@ ++/* ++ * Copyright 2015 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 "SoftAVCDec" ++#include ++ ++#include "ih264_typedefs.h" ++#include "iv.h" ++#include "ivd.h" ++#include "ih264d.h" ++#include "SoftAVCDec.h" ++ ++#include ++#include ++#include ++#include ++ ++namespace android { ++ ++#define componentName "video_decoder.avc" ++#define codingType OMX_VIDEO_CodingAVC ++#define CODEC_MIME_TYPE MEDIA_MIMETYPE_VIDEO_AVC ++ ++/** Function and structure definitions to keep code similar for each codec */ ++#define ivdec_api_function ih264d_api_function ++#define ivdext_create_ip_t ih264d_create_ip_t ++#define ivdext_create_op_t ih264d_create_op_t ++#define ivdext_delete_ip_t ih264d_delete_ip_t ++#define ivdext_delete_op_t ih264d_delete_op_t ++#define ivdext_ctl_set_num_cores_ip_t ih264d_ctl_set_num_cores_ip_t ++#define ivdext_ctl_set_num_cores_op_t ih264d_ctl_set_num_cores_op_t ++ ++#define IVDEXT_CMD_CTL_SET_NUM_CORES \ ++ (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES ++ ++static const CodecProfileLevel kProfileLevels[] = { ++ { OMX_VIDEO_AVCProfileConstrainedBaseline, OMX_VIDEO_AVCLevel52 }, ++ ++ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel52 }, ++ ++ { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel52 }, ++ ++ { OMX_VIDEO_AVCProfileConstrainedHigh, OMX_VIDEO_AVCLevel52 }, ++ ++ { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel52 }, ++}; ++ ++SoftAVC::SoftAVC( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SoftVideoDecoderOMXComponent( ++ name, componentName, codingType, ++ kProfileLevels, ARRAY_SIZE(kProfileLevels), ++ 320 /* width */, 240 /* height */, callbacks, ++ appData, component), ++ mCodecCtx(NULL), ++ mFlushOutBuffer(NULL), ++ mOmxColorFormat(OMX_COLOR_FormatYUV420Planar), ++ mIvColorFormat(IV_YUV_420P), ++ mChangingResolution(false), ++ mSignalledError(false), ++ mStride(mWidth), ++ mInputOffset(0){ ++ initPorts( ++ 1 /* numMinInputBuffers */, kNumBuffers, INPUT_BUF_SIZE, ++ 1 /* numMinOutputBuffers */, kNumBuffers, CODEC_MIME_TYPE); ++ ++ mTimeStart = mTimeEnd = systemTime(); ++ ++ // If input dump is enabled, then open create an empty file ++ GENERATE_FILE_NAMES(); ++ CREATE_DUMP_FILE(mInFile); ++} ++ ++SoftAVC::~SoftAVC() { ++ CHECK_EQ(deInitDecoder(), (status_t)OK); ++} ++ ++static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) { ++ UNUSED(ctxt); ++ return memalign(alignment, size); ++} ++ ++static void ivd_aligned_free(void *ctxt, void *buf) { ++ UNUSED(ctxt); ++ free(buf); ++ return; ++} ++ ++static size_t GetCPUCoreCount() { ++ long cpuCoreCount = 1; ++#if defined(_SC_NPROCESSORS_ONLN) ++ cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); ++#else ++ // _SC_NPROC_ONLN must be defined... ++ cpuCoreCount = sysconf(_SC_NPROC_ONLN); ++#endif ++ CHECK(cpuCoreCount >= 1); ++ ALOGV("Number of CPU cores: %ld", cpuCoreCount); ++ return (size_t)cpuCoreCount; ++} ++ ++void SoftAVC::logVersion() { ++ ivd_ctl_getversioninfo_ip_t s_ctl_ip; ++ ivd_ctl_getversioninfo_op_t s_ctl_op; ++ UWORD8 au1_buf[512]; ++ IV_API_CALL_STATUS_T status; ++ ++ s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION; ++ s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t); ++ s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t); ++ s_ctl_ip.pv_version_buffer = au1_buf; ++ s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf); ++ ++ status = ++ ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGE("Error in getting version number: 0x%x", ++ s_ctl_op.u4_error_code); ++ } else { ++ ALOGV("Ittiam decoder version number: %s", ++ (char *)s_ctl_ip.pv_version_buffer); ++ } ++ return; ++} ++ ++status_t SoftAVC::setParams(size_t stride) { ++ ivd_ctl_set_config_ip_t s_ctl_ip; ++ ivd_ctl_set_config_op_t s_ctl_op; ++ IV_API_CALL_STATUS_T status; ++ s_ctl_ip.u4_disp_wd = (UWORD32)stride; ++ s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE; ++ ++ s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT; ++ s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME; ++ s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS; ++ s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t); ++ s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t); ++ ++ ALOGV("Set the run-time (dynamic) parameters stride = %zu", stride); ++ status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGE("Error in setting the run-time parameters: 0x%x", ++ s_ctl_op.u4_error_code); ++ ++ return UNKNOWN_ERROR; ++ } ++ return OK; ++} ++ ++status_t SoftAVC::resetPlugin() { ++ mIsInFlush = false; ++ mReceivedEOS = false; ++ ++ memset(mTimeStamps, 0, sizeof(mTimeStamps)); ++ memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid)); ++ ++ /* Initialize both start and end times */ ++ mTimeStart = mTimeEnd = systemTime(); ++ ++ return OK; ++} ++ ++status_t SoftAVC::resetDecoder() { ++ ivd_ctl_reset_ip_t s_ctl_ip; ++ ivd_ctl_reset_op_t s_ctl_op; ++ IV_API_CALL_STATUS_T status; ++ ++ s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET; ++ s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t); ++ s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t); ++ ++ status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op); ++ if (IV_SUCCESS != status) { ++ ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code); ++ return UNKNOWN_ERROR; ++ } ++ mSignalledError = false; ++ ++ /* Set number of cores/threads to be used by the codec */ ++ setNumCores(); ++ ++ mStride = 0; ++ return OK; ++} ++ ++status_t SoftAVC::setNumCores() { ++ ivdext_ctl_set_num_cores_ip_t s_set_cores_ip; ++ ivdext_ctl_set_num_cores_op_t s_set_cores_op; ++ IV_API_CALL_STATUS_T status; ++ s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES; ++ s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES); ++ s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t); ++ s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t); ++ status = ivdec_api_function( ++ mCodecCtx, (void *)&s_set_cores_ip, (void *)&s_set_cores_op); ++ if (IV_SUCCESS != status) { ++ ALOGE("Error in setting number of cores: 0x%x", ++ s_set_cores_op.u4_error_code); ++ return UNKNOWN_ERROR; ++ } ++ return OK; ++} ++ ++status_t SoftAVC::setFlushMode() { ++ IV_API_CALL_STATUS_T status; ++ ivd_ctl_flush_ip_t s_video_flush_ip; ++ ivd_ctl_flush_op_t s_video_flush_op; ++ ++ s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH; ++ s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t); ++ s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t); ++ ++ /* Set the decoder in Flush mode, subsequent decode() calls will flush */ ++ status = ivdec_api_function( ++ mCodecCtx, (void *)&s_video_flush_ip, (void *)&s_video_flush_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status, ++ s_video_flush_op.u4_error_code); ++ return UNKNOWN_ERROR; ++ } ++ ++ mIsInFlush = true; ++ return OK; ++} ++ ++status_t SoftAVC::initDecoder() { ++ IV_API_CALL_STATUS_T status; ++ ++ mNumCores = GetCPUCoreCount(); ++ mCodecCtx = NULL; ++ ++ mStride = outputBufferWidth(); ++ ++ /* Initialize the decoder */ ++ { ++ ivdext_create_ip_t s_create_ip; ++ ivdext_create_op_t s_create_op; ++ ++ void *dec_fxns = (void *)ivdec_api_function; ++ ++ s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t); ++ s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE; ++ s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0; ++ s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t); ++ s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat; ++ s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc; ++ s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free; ++ s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL; ++ ++ status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGE("Error in create: 0x%x", ++ s_create_op.s_ivd_create_op_t.u4_error_code); ++ deInitDecoder(); ++ mCodecCtx = NULL; ++ return UNKNOWN_ERROR; ++ } ++ ++ mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle; ++ mCodecCtx->pv_fxns = dec_fxns; ++ mCodecCtx->u4_size = sizeof(iv_obj_t); ++ } ++ ++ /* Reset the plugin state */ ++ resetPlugin(); ++ ++ /* Set the run time (dynamic) parameters */ ++ setParams(mStride); ++ ++ /* Set number of cores/threads to be used by the codec */ ++ setNumCores(); ++ ++ /* Get codec version */ ++ logVersion(); ++ ++ mFlushNeeded = false; ++ return OK; ++} ++ ++status_t SoftAVC::deInitDecoder() { ++ IV_API_CALL_STATUS_T status; ++ ++ if (mCodecCtx) { ++ ivdext_delete_ip_t s_delete_ip; ++ ivdext_delete_op_t s_delete_op; ++ ++ s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t); ++ s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE; ++ ++ s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t); ++ ++ status = ivdec_api_function(mCodecCtx, (void *)&s_delete_ip, (void *)&s_delete_op); ++ if (status != IV_SUCCESS) { ++ ALOGE("Error in delete: 0x%x", ++ s_delete_op.s_ivd_delete_op_t.u4_error_code); ++ return UNKNOWN_ERROR; ++ } ++ } ++ ++ ++ mChangingResolution = false; ++ ++ return OK; ++} ++ ++void SoftAVC::onReset() { ++ SoftVideoDecoderOMXComponent::onReset(); ++ ++ mSignalledError = false; ++ mInputOffset = 0; ++ resetDecoder(); ++ resetPlugin(); ++} ++ ++bool SoftAVC::getVUIParams() { ++ IV_API_CALL_STATUS_T status; ++ ih264d_ctl_get_vui_params_ip_t s_ctl_get_vui_params_ip; ++ ih264d_ctl_get_vui_params_op_t s_ctl_get_vui_params_op; ++ ++ s_ctl_get_vui_params_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_ctl_get_vui_params_ip.e_sub_cmd = ++ (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_GET_VUI_PARAMS; ++ ++ s_ctl_get_vui_params_ip.u4_size = ++ sizeof(ih264d_ctl_get_vui_params_ip_t); ++ ++ s_ctl_get_vui_params_op.u4_size = sizeof(ih264d_ctl_get_vui_params_op_t); ++ ++ status = ivdec_api_function( ++ (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_vui_params_ip, ++ (void *)&s_ctl_get_vui_params_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGW("Error in getting VUI params: 0x%x", ++ s_ctl_get_vui_params_op.u4_error_code); ++ return false; ++ } ++ ++ int32_t primaries = s_ctl_get_vui_params_op.u1_colour_primaries; ++ int32_t transfer = s_ctl_get_vui_params_op.u1_tfr_chars; ++ int32_t coeffs = s_ctl_get_vui_params_op.u1_matrix_coeffs; ++ bool fullRange = s_ctl_get_vui_params_op.u1_video_full_range_flag; ++ ++ ColorAspects colorAspects; ++ ColorUtils::convertIsoColorAspectsToCodecAspects( ++ primaries, transfer, coeffs, fullRange, colorAspects); ++ ++ // Update color aspects if necessary. ++ if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) { ++ mBitstreamColorAspects = colorAspects; ++ status_t err = handleColorAspectsChange(); ++ CHECK(err == OK); ++ } ++ return true; ++} ++ ++bool SoftAVC::setDecodeArgs( ++ ivd_video_decode_ip_t *ps_dec_ip, ++ ivd_video_decode_op_t *ps_dec_op, ++ OMX_BUFFERHEADERTYPE *inHeader, ++ OMX_BUFFERHEADERTYPE *outHeader, ++ size_t timeStampIx) { ++ size_t sizeY = outputBufferWidth() * outputBufferHeight(); ++ size_t sizeUV; ++ ++ ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t); ++ ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t); ++ ++ ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE; ++ ++ /* When in flush and after EOS with zero byte input, ++ * inHeader is set to zero. Hence check for non-null */ ++ if (inHeader) { ++ ps_dec_ip->u4_ts = timeStampIx; ++ ps_dec_ip->pv_stream_buffer = ++ inHeader->pBuffer + inHeader->nOffset + mInputOffset; ++ ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen - mInputOffset; ++ } else { ++ ps_dec_ip->u4_ts = 0; ++ ps_dec_ip->pv_stream_buffer = NULL; ++ ps_dec_ip->u4_num_Bytes = 0; ++ } ++ ++ sizeUV = sizeY / 4; ++ ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY; ++ ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV; ++ ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV; ++ ++ uint8_t *pBuf; ++ if (outHeader) { ++ if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) { ++ android_errorWriteLog(0x534e4554, "27833616"); ++ return false; ++ } ++ pBuf = outHeader->pBuffer; ++ } else { ++ // mFlushOutBuffer always has the right size. ++ pBuf = mFlushOutBuffer; ++ } ++ ++ ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf; ++ ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY; ++ ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV; ++ ps_dec_ip->s_out_buffer.u4_num_bufs = 3; ++ return true; ++} ++void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) { ++ /* Once the output buffers are flushed, ignore any buffers that are held in decoder */ ++ if (kOutputPortIndex == portIndex) { ++ setFlushMode(); ++ ++ /* Allocate a picture buffer to flushed data */ ++ uint32_t displayStride = outputBufferWidth(); ++ uint32_t displayHeight = outputBufferHeight(); ++ ++ uint32_t bufferSize = displayStride * displayHeight * 3 / 2; ++ mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize); ++ if (NULL == mFlushOutBuffer) { ++ ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize); ++ return; ++ } ++ ++ while (true) { ++ ivd_video_decode_ip_t s_dec_ip; ++ ivd_video_decode_op_t s_dec_op; ++ IV_API_CALL_STATUS_T status; ++ ++ setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0); ++ ++ status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); ++ if (0 == s_dec_op.u4_output_present) { ++ resetPlugin(); ++ break; ++ } ++ } ++ ++ if (mFlushOutBuffer) { ++ free(mFlushOutBuffer); ++ mFlushOutBuffer = NULL; ++ } ++ } else { ++ mInputOffset = 0; ++ } ++} ++ ++void SoftAVC::onQueueFilled(OMX_U32 portIndex) { ++ UNUSED(portIndex); ++ OMX_BUFFERHEADERTYPE *inHeader = NULL; ++ BufferInfo *inInfo = NULL; ++ ++ if (mSignalledError) { ++ return; ++ } ++ if (mOutputPortSettingsChange != NONE) { ++ return; ++ } ++ ++ if (NULL == mCodecCtx) { ++ if (OK != initDecoder()) { ++ ALOGE("Failed to initialize decoder"); ++ notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ } ++ if (outputBufferWidth() != mStride) { ++ /* Set the run-time (dynamic) parameters */ ++ mStride = outputBufferWidth(); ++ setParams(mStride); ++ } ++ ++ List &inQueue = getPortQueue(kInputPortIndex); ++ List &outQueue = getPortQueue(kOutputPortIndex); ++ ++ while (!outQueue.empty()) { ++ BufferInfo *outInfo; ++ OMX_BUFFERHEADERTYPE *outHeader; ++ size_t timeStampIx = 0; ++ ++ if (!mIsInFlush && (NULL == inHeader)) { ++ if (!inQueue.empty()) { ++ inInfo = *inQueue.begin(); ++ inHeader = inInfo->mHeader; ++ if (inHeader == NULL) { ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ continue; ++ } ++ } else { ++ break; ++ } ++ } ++ ++ outInfo = *outQueue.begin(); ++ outHeader = outInfo->mHeader; ++ outHeader->nFlags = 0; ++ outHeader->nTimeStamp = 0; ++ outHeader->nOffset = 0; ++ ++ if (inHeader != NULL) { ++ if (inHeader->nFilledLen == 0) { ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ ++ if (!(inHeader->nFlags & OMX_BUFFERFLAG_EOS)) { ++ return; ++ } ++ ++ mReceivedEOS = true; ++ inHeader = NULL; ++ setFlushMode(); ++ } else if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ mReceivedEOS = true; ++ } ++ } ++ ++ /* Get a free slot in timestamp array to hold input timestamp */ ++ { ++ size_t i; ++ timeStampIx = 0; ++ for (i = 0; i < MAX_TIME_STAMPS; i++) { ++ if (!mTimeStampsValid[i]) { ++ timeStampIx = i; ++ break; ++ } ++ } ++ if (inHeader != NULL) { ++ mTimeStampsValid[timeStampIx] = true; ++ mTimeStamps[timeStampIx] = inHeader->nTimeStamp; ++ } ++ } ++ ++ { ++ ivd_video_decode_ip_t s_dec_ip; ++ ivd_video_decode_op_t s_dec_op; ++ nsecs_t timeDelay, timeTaken; ++ ++ if (!setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) { ++ ALOGE("Decoder arg setup failed"); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ // If input dump is enabled, then write to file ++ DUMP_TO_FILE(mInFile, s_dec_ip.pv_stream_buffer, s_dec_ip.u4_num_Bytes, mInputOffset); ++ ++ mTimeStart = systemTime(); ++ /* Compute time elapsed between end of previous decode() ++ * to start of current decode() */ ++ timeDelay = mTimeStart - mTimeEnd; ++ ++ IV_API_CALL_STATUS_T status; ++ status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); ++ ++ bool unsupportedResolution = ++ (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_dec_op.u4_error_code & IVD_ERROR_MASK)); ++ ++ /* Check for unsupported dimensions */ ++ if (unsupportedResolution) { ++ ALOGE("Unsupported resolution : %dx%d", mWidth, mHeight); ++ notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ bool allocationFailed = (IVD_MEM_ALLOC_FAILED == (s_dec_op.u4_error_code & IVD_ERROR_MASK)); ++ if (allocationFailed) { ++ ALOGE("Allocation failure in decoder"); ++ notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ if (IS_IVD_FATAL_ERROR(s_dec_op.u4_error_code)) { ++ ALOGE("Fatal Error : 0x%x", s_dec_op.u4_error_code); ++ notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & IVD_ERROR_MASK)); ++ ++ getVUIParams(); ++ ++ mTimeEnd = systemTime(); ++ /* Compute time taken for decode() */ ++ timeTaken = mTimeEnd - mTimeStart; ++ ++ ALOGV("timeTaken=%6lldus delay=%6lldus numBytes=%6d", ++ (long long) (timeTaken / 1000LL), (long long) (timeDelay / 1000LL), ++ s_dec_op.u4_num_bytes_consumed); ++ if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) { ++ mFlushNeeded = true; ++ } ++ ++ if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) { ++ /* If the input did not contain picture data, then ignore ++ * the associated timestamp */ ++ mTimeStampsValid[timeStampIx] = false; ++ } ++ ++ // If the decoder is in the changing resolution mode and there is no output present, ++ // that means the switching is done and it's ready to reset the decoder and the plugin. ++ if (mChangingResolution && !s_dec_op.u4_output_present) { ++ mChangingResolution = false; ++ resetDecoder(); ++ resetPlugin(); ++ mStride = outputBufferWidth(); ++ setParams(mStride); ++ continue; ++ } ++ ++ if (resChanged) { ++ mChangingResolution = true; ++ if (mFlushNeeded) { ++ setFlushMode(); ++ } ++ continue; ++ } ++ ++ // Combine the resolution change and coloraspects change in one PortSettingChange event ++ // if necessary. ++ if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) { ++ uint32_t width = s_dec_op.u4_pic_wd; ++ uint32_t height = s_dec_op.u4_pic_ht; ++ bool portWillReset = false; ++ handlePortSettingsChange(&portWillReset, width, height); ++ if (portWillReset) { ++ resetDecoder(); ++ resetPlugin(); ++ return; ++ } ++ } else if (mUpdateColorAspects) { ++ notify(OMX_EventPortSettingsChanged, kOutputPortIndex, ++ kDescribeColorAspectsIndex, NULL); ++ mUpdateColorAspects = false; ++ return; ++ } ++ ++ if (s_dec_op.u4_output_present) { ++ outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2; ++ ++ outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts]; ++ mTimeStampsValid[s_dec_op.u4_ts] = false; ++ ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ outInfo = NULL; ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ } else if (mIsInFlush) { ++ /* If in flush mode and no output is returned by the codec, ++ * then come out of flush mode */ ++ mIsInFlush = false; ++ ++ /* If EOS was recieved on input port and there is no output ++ * from the codec, then signal EOS on output port */ ++ if (mReceivedEOS) { ++ outHeader->nFilledLen = 0; ++ outHeader->nFlags |= OMX_BUFFERFLAG_EOS; ++ ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ outInfo = NULL; ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ resetPlugin(); ++ } ++ } ++ mInputOffset += s_dec_op.u4_num_bytes_consumed; ++ } ++ // If more than 4 bytes are remaining in input, then do not release it ++ if (inHeader != NULL && ((inHeader->nFilledLen - mInputOffset) <= 4)) { ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ mInputOffset = 0; ++ ++ /* If input EOS is seen and decoder is not in flush mode, ++ * set the decoder in flush mode. ++ * There can be a case where EOS is sent along with last picture data ++ * In that case, only after decoding that input data, decoder has to be ++ * put in flush. This case is handled here */ ++ ++ if (mReceivedEOS && !mIsInFlush) { ++ setFlushMode(); ++ } ++ } ++ } ++} ++ ++int SoftAVC::getColorAspectPreference() { ++ return kPreferBitstream; ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) { ++ return new android::SoftAVC(name, callbacks, appData, component); ++} +diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.h b/media/libstagefright/codecs/avcdec/SoftAVCDec.h +new file mode 100644 +index 0000000..679ed3e +--- /dev/null ++++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.h +@@ -0,0 +1,168 @@ ++/* ++ * Copyright 2015 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 SOFT_H264_DEC_H_ ++ ++#define SOFT_H264_DEC_H_ ++ ++#include ++#include ++ ++namespace android { ++ ++/** Number of entries in the time-stamp array */ ++#define MAX_TIME_STAMPS 64 ++ ++/** Maximum number of cores supported by the codec */ ++#define CODEC_MAX_NUM_CORES 4 ++ ++#define CODEC_MAX_WIDTH 1920 ++ ++#define CODEC_MAX_HEIGHT 1088 ++ ++/** Input buffer size */ ++#define INPUT_BUF_SIZE (1024 * 1024) ++ ++#define MIN(a, b) ((a) < (b)) ? (a) : (b) ++ ++/** Used to remove warnings about unused parameters */ ++#define UNUSED(x) ((void)(x)) ++ ++struct SoftAVC : public SoftVideoDecoderOMXComponent { ++ SoftAVC(const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component); ++ ++protected: ++ virtual ~SoftAVC(); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ virtual void onPortFlushCompleted(OMX_U32 portIndex); ++ virtual void onReset(); ++ virtual int getColorAspectPreference(); ++private: ++ // Number of input and output buffers ++ enum { ++ kNumBuffers = 8 ++ }; ++ ++ iv_obj_t *mCodecCtx; // Codec context ++ ++ size_t mNumCores; // Number of cores to be uesd by the codec ++ ++ nsecs_t mTimeStart; // Time at the start of decode() ++ nsecs_t mTimeEnd; // Time at the end of decode() ++ ++ // Internal buffer to be used to flush out the buffers from decoder ++ uint8_t *mFlushOutBuffer; ++ ++ // Status of entries in the timestamp array ++ bool mTimeStampsValid[MAX_TIME_STAMPS]; ++ ++ // Timestamp array - Since codec does not take 64 bit timestamps, ++ // they are maintained in the plugin ++ OMX_S64 mTimeStamps[MAX_TIME_STAMPS]; ++ ++#ifdef FILE_DUMP_ENABLE ++ char mInFile[200]; ++#endif /* FILE_DUMP_ENABLE */ ++ ++ OMX_COLOR_FORMATTYPE mOmxColorFormat; // OMX Color format ++ IV_COLOR_FORMAT_T mIvColorFormat; // Ittiam Color format ++ ++ bool mIsInFlush; // codec is flush mode ++ bool mReceivedEOS; // EOS is receieved on input port ++ ++ // The input stream has changed to a different resolution, which is still supported by the ++ // codec. So the codec is switching to decode the new resolution. ++ bool mChangingResolution; ++ bool mFlushNeeded; ++ bool mSignalledError; ++ size_t mStride; ++ size_t mInputOffset; ++ ++ status_t initDecoder(); ++ status_t deInitDecoder(); ++ status_t setFlushMode(); ++ status_t setParams(size_t stride); ++ void logVersion(); ++ status_t setNumCores(); ++ status_t resetDecoder(); ++ status_t resetPlugin(); ++ ++ ++ bool setDecodeArgs( ++ ivd_video_decode_ip_t *ps_dec_ip, ++ ivd_video_decode_op_t *ps_dec_op, ++ OMX_BUFFERHEADERTYPE *inHeader, ++ OMX_BUFFERHEADERTYPE *outHeader, ++ size_t timeStampIx); ++ ++ bool getVUIParams(); ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftAVC); ++}; ++ ++#ifdef FILE_DUMP_ENABLE ++ ++#define INPUT_DUMP_PATH "/sdcard/media/avcd_input" ++#define INPUT_DUMP_EXT "h264" ++ ++#define GENERATE_FILE_NAMES() { \ ++ strcpy(mInFile, ""); \ ++ sprintf(mInFile, "%s_%lld.%s", INPUT_DUMP_PATH, \ ++ (long long) mTimeStart, \ ++ INPUT_DUMP_EXT); \ ++} ++ ++#define CREATE_DUMP_FILE(m_filename) { \ ++ FILE *fp = fopen(m_filename, "wb"); \ ++ if (fp != NULL) { \ ++ fclose(fp); \ ++ } else { \ ++ ALOGD("Could not open file %s", m_filename); \ ++ } \ ++} ++#define DUMP_TO_FILE(m_filename, m_buf, m_size, m_offset)\ ++{ \ ++ FILE *fp = fopen(m_filename, "ab"); \ ++ if (fp != NULL && m_buf != NULL && m_offset == 0) { \ ++ int i; \ ++ i = fwrite(m_buf, 1, m_size, fp); \ ++ ALOGD("fwrite ret %d to write %d", i, m_size); \ ++ if (i != (int) m_size) { \ ++ ALOGD("Error in fwrite, returned %d", i); \ ++ perror("Error in write to file"); \ ++ } \ ++ } else if (fp == NULL) { \ ++ ALOGD("Could not write to file %s", m_filename);\ ++ } \ ++ if (fp) { \ ++ fclose(fp); \ ++ } \ ++} ++#else /* FILE_DUMP_ENABLE */ ++#define INPUT_DUMP_PATH ++#define INPUT_DUMP_EXT ++#define OUTPUT_DUMP_PATH ++#define OUTPUT_DUMP_EXT ++#define GENERATE_FILE_NAMES() ++#define CREATE_DUMP_FILE(m_filename) ++#define DUMP_TO_FILE(m_filename, m_buf, m_size, m_offset) ++#endif /* FILE_DUMP_ENABLE */ ++ ++} // namespace android ++ ++#endif // SOFT_H264_DEC_H_ +diff --git a/media/libstagefright/codecs/avcdec/exports.lds b/media/libstagefright/codecs/avcdec/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/avcdec/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/avcenc/Android.bp b/media/libstagefright/codecs/avcenc/Android.bp +new file mode 100644 +index 0000000..586088c +--- /dev/null ++++ b/media/libstagefright/codecs/avcenc/Android.bp +@@ -0,0 +1,34 @@ ++package { ++ // See: http://go/android-license-faq ++ // A large-scale-change added 'default_applicable_licenses' to import ++ // all of the 'license_kinds' from "frameworks_av_media_libstagefright_license" ++ // to get the below license kinds: ++ // SPDX-license-identifier-Apache-2.0 ++ default_applicable_licenses: ["frameworks_av_media_libstagefright_license"], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_avcenc", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ static_libs: ["libavcenc"], ++ srcs: ["SoftAVCEnc.cpp"], ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ ], ++ cfi: true, ++ config: { ++ cfi_assembly_support: true, ++ }, ++ }, ++ ++ cflags: [ ++ "-Wall", ++ "-Wno-unused-variable", ++ ], ++ ldflags: ["-Wl,-Bsymbolic"], ++ ++ version_script: "exports.lds", ++} +diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp +new file mode 100644 +index 0000000..01174c9 +--- /dev/null ++++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp +@@ -0,0 +1,1515 @@ ++/* ++ * Copyright 2015 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 "SoftAVCEnc" ++#include ++#include ++ ++#include "OMX_Video.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ih264_typedefs.h" ++#include "iv2.h" ++#include "ive2.h" ++#include "ih264e.h" ++#include "SoftAVCEnc.h" ++ ++namespace android { ++ ++ #define ive_api_function ih264e_api_function ++ ++template ++static void InitOMXParams(T *params) { ++ params->nSize = sizeof(T); ++ params->nVersion.s.nVersionMajor = 1; ++ params->nVersion.s.nVersionMinor = 0; ++ params->nVersion.s.nRevision = 0; ++ params->nVersion.s.nStep = 0; ++} ++ ++struct LevelConversion { ++ OMX_VIDEO_AVCLEVELTYPE omxLevel; ++ WORD32 avcLevel; ++}; ++ ++static LevelConversion ConversionTable[] = { ++ { OMX_VIDEO_AVCLevel1, 10 }, ++ { OMX_VIDEO_AVCLevel1b, 9 }, ++ { OMX_VIDEO_AVCLevel11, 11 }, ++ { OMX_VIDEO_AVCLevel12, 12 }, ++ { OMX_VIDEO_AVCLevel13, 13 }, ++ { OMX_VIDEO_AVCLevel2, 20 }, ++ { OMX_VIDEO_AVCLevel21, 21 }, ++ { OMX_VIDEO_AVCLevel22, 22 }, ++ { OMX_VIDEO_AVCLevel3, 30 }, ++ { OMX_VIDEO_AVCLevel31, 31 }, ++ { OMX_VIDEO_AVCLevel32, 32 }, ++ { OMX_VIDEO_AVCLevel4, 40 }, ++ { OMX_VIDEO_AVCLevel41, 41 }, ++ { OMX_VIDEO_AVCLevel42, 42 }, ++ { OMX_VIDEO_AVCLevel5, 50 }, ++ { OMX_VIDEO_AVCLevel51, 51 }, ++}; ++ ++static const CodecProfileLevel kProfileLevels[] = { ++ { OMX_VIDEO_AVCProfileConstrainedBaseline, OMX_VIDEO_AVCLevel41 }, ++ ++ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel41 }, ++ ++ { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel41 }, ++}; ++ ++static size_t GetCPUCoreCount() { ++ long cpuCoreCount = 1; ++#if defined(_SC_NPROCESSORS_ONLN) ++ cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); ++#else ++ // _SC_NPROC_ONLN must be defined... ++ cpuCoreCount = sysconf(_SC_NPROC_ONLN); ++#endif ++ CHECK(cpuCoreCount >= 1); ++ ALOGV("Number of CPU cores: %ld", cpuCoreCount); ++ return (size_t)cpuCoreCount; ++} ++ ++static status_t ConvertOmxAvcLevelToAvcSpecLevel( ++ OMX_VIDEO_AVCLEVELTYPE omxLevel, WORD32 *avcLevel) { ++ for (size_t i = 0; i < NELEM(ConversionTable); ++i) { ++ if (omxLevel == ConversionTable[i].omxLevel) { ++ *avcLevel = ConversionTable[i].avcLevel; ++ return OK; ++ } ++ } ++ ++ ALOGE("ConvertOmxAvcLevelToAvcSpecLevel: %d level not supported", ++ (int32_t)omxLevel); ++ ++ return BAD_VALUE; ++} ++ ++static status_t ConvertAvcSpecLevelToOmxAvcLevel( ++ WORD32 avcLevel, OMX_VIDEO_AVCLEVELTYPE *omxLevel) { ++ for (size_t i = 0; i < NELEM(ConversionTable); ++i) { ++ if (avcLevel == ConversionTable[i].avcLevel) { ++ *omxLevel = ConversionTable[i].omxLevel; ++ return OK; ++ } ++ } ++ ++ ALOGE("ConvertAvcSpecLevelToOmxAvcLevel: %d level not supported", ++ (int32_t)avcLevel); ++ ++ return BAD_VALUE; ++} ++ ++ ++SoftAVC::SoftAVC( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SoftVideoEncoderOMXComponent( ++ name, "video_encoder.avc", OMX_VIDEO_CodingAVC, ++ kProfileLevels, NELEM(kProfileLevels), ++ 176 /* width */, 144 /* height */, ++ callbacks, appData, component), ++ mUpdateFlag(0), ++ mIvVideoColorFormat(IV_YUV_420P), ++ mAVCEncProfile(IV_PROFILE_BASE), ++ mAVCEncLevel(41), ++ mStarted(false), ++ mSawInputEOS(false), ++ mSawOutputEOS(false), ++ mSignalledError(false), ++ mCodecCtx(NULL) { ++ ++ initPorts(kNumBuffers, kNumBuffers, ((mWidth * mHeight * 3) >> 1), ++ MEDIA_MIMETYPE_VIDEO_AVC, 2); ++ ++ // If dump is enabled, then open create an empty file ++ GENERATE_FILE_NAMES(); ++ CREATE_DUMP_FILE(mInFile); ++ CREATE_DUMP_FILE(mOutFile); ++ memset(mConversionBuffers, 0, sizeof(mConversionBuffers)); ++ memset(mInputBufferInfo, 0, sizeof(mInputBufferInfo)); ++ ++ initEncParams(); ++ ++} ++ ++SoftAVC::~SoftAVC() { ++ releaseEncoder(); ++ List &outQueue = getPortQueue(1); ++ List &inQueue = getPortQueue(0); ++ CHECK(outQueue.empty()); ++ CHECK(inQueue.empty()); ++} ++ ++void SoftAVC::initEncParams() { ++ mCodecCtx = NULL; ++ mMemRecords = NULL; ++ mNumMemRecords = DEFAULT_MEM_REC_CNT; ++ mHeaderGenerated = 0; ++ mNumCores = GetCPUCoreCount(); ++ mArch = DEFAULT_ARCH; ++ mSliceMode = DEFAULT_SLICE_MODE; ++ mSliceParam = DEFAULT_SLICE_PARAM; ++ mHalfPelEnable = DEFAULT_HPEL; ++ mIInterval = DEFAULT_I_INTERVAL; ++ mIDRInterval = DEFAULT_IDR_INTERVAL; ++ mDisableDeblkLevel = DEFAULT_DISABLE_DEBLK_LEVEL; ++ mEnableFastSad = DEFAULT_ENABLE_FAST_SAD; ++ mEnableAltRef = DEFAULT_ENABLE_ALT_REF; ++ mEncSpeed = DEFAULT_ENC_SPEED; ++ mIntra4x4 = DEFAULT_INTRA4x4; ++ mConstrainedIntraFlag = DEFAULT_CONSTRAINED_INTRA; ++ mAIRMode = DEFAULT_AIR; ++ mAIRRefreshPeriod = DEFAULT_AIR_REFRESH_PERIOD; ++ mPSNREnable = DEFAULT_PSNR_ENABLE; ++ mReconEnable = DEFAULT_RECON_ENABLE; ++ mEntropyMode = DEFAULT_ENTROPY_MODE; ++ mBframes = DEFAULT_B_FRAMES; ++ ++ gettimeofday(&mTimeStart, NULL); ++ gettimeofday(&mTimeEnd, NULL); ++ ++} ++ ++ ++OMX_ERRORTYPE SoftAVC::setDimensions() { ++ ive_ctl_set_dimensions_ip_t s_dimensions_ip; ++ ive_ctl_set_dimensions_op_t s_dimensions_op; ++ IV_STATUS_T status; ++ ++ s_dimensions_ip.e_cmd = IVE_CMD_VIDEO_CTL; ++ s_dimensions_ip.e_sub_cmd = IVE_CMD_CTL_SET_DIMENSIONS; ++ s_dimensions_ip.u4_ht = mHeight; ++ s_dimensions_ip.u4_wd = mWidth; ++ ++ s_dimensions_ip.u4_timestamp_high = -1; ++ s_dimensions_ip.u4_timestamp_low = -1; ++ ++ s_dimensions_ip.u4_size = sizeof(ive_ctl_set_dimensions_ip_t); ++ s_dimensions_op.u4_size = sizeof(ive_ctl_set_dimensions_op_t); ++ ++ status = ive_api_function(mCodecCtx, &s_dimensions_ip, &s_dimensions_op); ++ if (status != IV_SUCCESS) { ++ ALOGE("Unable to set frame dimensions = 0x%x\n", ++ s_dimensions_op.u4_error_code); ++ return OMX_ErrorUndefined; ++ } ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftAVC::setNumCores() { ++ IV_STATUS_T status; ++ ive_ctl_set_num_cores_ip_t s_num_cores_ip; ++ ive_ctl_set_num_cores_op_t s_num_cores_op; ++ s_num_cores_ip.e_cmd = IVE_CMD_VIDEO_CTL; ++ s_num_cores_ip.e_sub_cmd = IVE_CMD_CTL_SET_NUM_CORES; ++ s_num_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_CORES); ++ s_num_cores_ip.u4_timestamp_high = -1; ++ s_num_cores_ip.u4_timestamp_low = -1; ++ s_num_cores_ip.u4_size = sizeof(ive_ctl_set_num_cores_ip_t); ++ ++ s_num_cores_op.u4_size = sizeof(ive_ctl_set_num_cores_op_t); ++ ++ status = ive_api_function( ++ mCodecCtx, (void *) &s_num_cores_ip, (void *) &s_num_cores_op); ++ if (status != IV_SUCCESS) { ++ ALOGE("Unable to set processor params = 0x%x\n", ++ s_num_cores_op.u4_error_code); ++ return OMX_ErrorUndefined; ++ } ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftAVC::setFrameRate() { ++ ive_ctl_set_frame_rate_ip_t s_frame_rate_ip; ++ ive_ctl_set_frame_rate_op_t s_frame_rate_op; ++ IV_STATUS_T status; ++ ++ s_frame_rate_ip.e_cmd = IVE_CMD_VIDEO_CTL; ++ s_frame_rate_ip.e_sub_cmd = IVE_CMD_CTL_SET_FRAMERATE; ++ ++ s_frame_rate_ip.u4_src_frame_rate = mFramerate >> 16; ++ s_frame_rate_ip.u4_tgt_frame_rate = mFramerate >> 16; ++ ++ s_frame_rate_ip.u4_timestamp_high = -1; ++ s_frame_rate_ip.u4_timestamp_low = -1; ++ ++ s_frame_rate_ip.u4_size = sizeof(ive_ctl_set_frame_rate_ip_t); ++ s_frame_rate_op.u4_size = sizeof(ive_ctl_set_frame_rate_op_t); ++ ++ status = ive_api_function(mCodecCtx, &s_frame_rate_ip, &s_frame_rate_op); ++ if (status != IV_SUCCESS) { ++ ALOGE("Unable to set frame rate = 0x%x\n", ++ s_frame_rate_op.u4_error_code); ++ return OMX_ErrorUndefined; ++ } ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftAVC::setIpeParams() { ++ ive_ctl_set_ipe_params_ip_t s_ipe_params_ip; ++ ive_ctl_set_ipe_params_op_t s_ipe_params_op; ++ IV_STATUS_T status; ++ ++ s_ipe_params_ip.e_cmd = IVE_CMD_VIDEO_CTL; ++ s_ipe_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_IPE_PARAMS; ++ ++ s_ipe_params_ip.u4_enable_intra_4x4 = mIntra4x4; ++ s_ipe_params_ip.u4_enc_speed_preset = mEncSpeed; ++ s_ipe_params_ip.u4_constrained_intra_pred = mConstrainedIntraFlag; ++ ++ s_ipe_params_ip.u4_timestamp_high = -1; ++ s_ipe_params_ip.u4_timestamp_low = -1; ++ ++ s_ipe_params_ip.u4_size = sizeof(ive_ctl_set_ipe_params_ip_t); ++ s_ipe_params_op.u4_size = sizeof(ive_ctl_set_ipe_params_op_t); ++ ++ status = ive_api_function(mCodecCtx, &s_ipe_params_ip, &s_ipe_params_op); ++ if (status != IV_SUCCESS) { ++ ALOGE("Unable to set ipe params = 0x%x\n", ++ s_ipe_params_op.u4_error_code); ++ return OMX_ErrorUndefined; ++ } ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftAVC::setBitRate() { ++ ive_ctl_set_bitrate_ip_t s_bitrate_ip; ++ ive_ctl_set_bitrate_op_t s_bitrate_op; ++ IV_STATUS_T status; ++ ++ s_bitrate_ip.e_cmd = IVE_CMD_VIDEO_CTL; ++ s_bitrate_ip.e_sub_cmd = IVE_CMD_CTL_SET_BITRATE; ++ ++ s_bitrate_ip.u4_target_bitrate = mBitrate; ++ ++ s_bitrate_ip.u4_timestamp_high = -1; ++ s_bitrate_ip.u4_timestamp_low = -1; ++ ++ s_bitrate_ip.u4_size = sizeof(ive_ctl_set_bitrate_ip_t); ++ s_bitrate_op.u4_size = sizeof(ive_ctl_set_bitrate_op_t); ++ ++ status = ive_api_function(mCodecCtx, &s_bitrate_ip, &s_bitrate_op); ++ if (status != IV_SUCCESS) { ++ ALOGE("Unable to set bit rate = 0x%x\n", s_bitrate_op.u4_error_code); ++ return OMX_ErrorUndefined; ++ } ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftAVC::setFrameType(IV_PICTURE_CODING_TYPE_T e_frame_type) { ++ ive_ctl_set_frame_type_ip_t s_frame_type_ip; ++ ive_ctl_set_frame_type_op_t s_frame_type_op; ++ IV_STATUS_T status; ++ s_frame_type_ip.e_cmd = IVE_CMD_VIDEO_CTL; ++ s_frame_type_ip.e_sub_cmd = IVE_CMD_CTL_SET_FRAMETYPE; ++ ++ s_frame_type_ip.e_frame_type = e_frame_type; ++ ++ s_frame_type_ip.u4_timestamp_high = -1; ++ s_frame_type_ip.u4_timestamp_low = -1; ++ ++ s_frame_type_ip.u4_size = sizeof(ive_ctl_set_frame_type_ip_t); ++ s_frame_type_op.u4_size = sizeof(ive_ctl_set_frame_type_op_t); ++ ++ status = ive_api_function(mCodecCtx, &s_frame_type_ip, &s_frame_type_op); ++ if (status != IV_SUCCESS) { ++ ALOGE("Unable to set frame type = 0x%x\n", ++ s_frame_type_op.u4_error_code); ++ return OMX_ErrorUndefined; ++ } ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftAVC::setQp() { ++ ive_ctl_set_qp_ip_t s_qp_ip; ++ ive_ctl_set_qp_op_t s_qp_op; ++ IV_STATUS_T status; ++ ++ s_qp_ip.e_cmd = IVE_CMD_VIDEO_CTL; ++ s_qp_ip.e_sub_cmd = IVE_CMD_CTL_SET_QP; ++ ++ s_qp_ip.u4_i_qp = DEFAULT_I_QP; ++ s_qp_ip.u4_i_qp_max = DEFAULT_QP_MAX; ++ s_qp_ip.u4_i_qp_min = DEFAULT_QP_MIN; ++ ++ s_qp_ip.u4_p_qp = DEFAULT_P_QP; ++ s_qp_ip.u4_p_qp_max = DEFAULT_QP_MAX; ++ s_qp_ip.u4_p_qp_min = DEFAULT_QP_MIN; ++ ++ s_qp_ip.u4_b_qp = DEFAULT_P_QP; ++ s_qp_ip.u4_b_qp_max = DEFAULT_QP_MAX; ++ s_qp_ip.u4_b_qp_min = DEFAULT_QP_MIN; ++ ++ s_qp_ip.u4_timestamp_high = -1; ++ s_qp_ip.u4_timestamp_low = -1; ++ ++ s_qp_ip.u4_size = sizeof(ive_ctl_set_qp_ip_t); ++ s_qp_op.u4_size = sizeof(ive_ctl_set_qp_op_t); ++ ++ status = ive_api_function(mCodecCtx, &s_qp_ip, &s_qp_op); ++ if (status != IV_SUCCESS) { ++ ALOGE("Unable to set qp 0x%x\n", s_qp_op.u4_error_code); ++ return OMX_ErrorUndefined; ++ } ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftAVC::setEncMode(IVE_ENC_MODE_T e_enc_mode) { ++ IV_STATUS_T status; ++ ive_ctl_set_enc_mode_ip_t s_enc_mode_ip; ++ ive_ctl_set_enc_mode_op_t s_enc_mode_op; ++ ++ s_enc_mode_ip.e_cmd = IVE_CMD_VIDEO_CTL; ++ s_enc_mode_ip.e_sub_cmd = IVE_CMD_CTL_SET_ENC_MODE; ++ ++ s_enc_mode_ip.e_enc_mode = e_enc_mode; ++ ++ s_enc_mode_ip.u4_timestamp_high = -1; ++ s_enc_mode_ip.u4_timestamp_low = -1; ++ ++ s_enc_mode_ip.u4_size = sizeof(ive_ctl_set_enc_mode_ip_t); ++ s_enc_mode_op.u4_size = sizeof(ive_ctl_set_enc_mode_op_t); ++ ++ status = ive_api_function(mCodecCtx, &s_enc_mode_ip, &s_enc_mode_op); ++ if (status != IV_SUCCESS) { ++ ALOGE("Unable to set in header encode mode = 0x%x\n", ++ s_enc_mode_op.u4_error_code); ++ return OMX_ErrorUndefined; ++ } ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftAVC::setVbvParams() { ++ ive_ctl_set_vbv_params_ip_t s_vbv_ip; ++ ive_ctl_set_vbv_params_op_t s_vbv_op; ++ IV_STATUS_T status; ++ ++ s_vbv_ip.e_cmd = IVE_CMD_VIDEO_CTL; ++ s_vbv_ip.e_sub_cmd = IVE_CMD_CTL_SET_VBV_PARAMS; ++ ++ s_vbv_ip.u4_vbv_buf_size = 0; ++ s_vbv_ip.u4_vbv_buffer_delay = 1000; ++ ++ s_vbv_ip.u4_timestamp_high = -1; ++ s_vbv_ip.u4_timestamp_low = -1; ++ ++ s_vbv_ip.u4_size = sizeof(ive_ctl_set_vbv_params_ip_t); ++ s_vbv_op.u4_size = sizeof(ive_ctl_set_vbv_params_op_t); ++ ++ status = ive_api_function(mCodecCtx, &s_vbv_ip, &s_vbv_op); ++ if (status != IV_SUCCESS) { ++ ALOGE("Unable to set VBC params = 0x%x\n", s_vbv_op.u4_error_code); ++ return OMX_ErrorUndefined; ++ } ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftAVC::setAirParams() { ++ ive_ctl_set_air_params_ip_t s_air_ip; ++ ive_ctl_set_air_params_op_t s_air_op; ++ IV_STATUS_T status; ++ ++ s_air_ip.e_cmd = IVE_CMD_VIDEO_CTL; ++ s_air_ip.e_sub_cmd = IVE_CMD_CTL_SET_AIR_PARAMS; ++ ++ s_air_ip.e_air_mode = mAIRMode; ++ s_air_ip.u4_air_refresh_period = mAIRRefreshPeriod; ++ ++ s_air_ip.u4_timestamp_high = -1; ++ s_air_ip.u4_timestamp_low = -1; ++ ++ s_air_ip.u4_size = sizeof(ive_ctl_set_air_params_ip_t); ++ s_air_op.u4_size = sizeof(ive_ctl_set_air_params_op_t); ++ ++ status = ive_api_function(mCodecCtx, &s_air_ip, &s_air_op); ++ if (status != IV_SUCCESS) { ++ ALOGE("Unable to set air params = 0x%x\n", s_air_op.u4_error_code); ++ return OMX_ErrorUndefined; ++ } ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftAVC::setMeParams() { ++ IV_STATUS_T status; ++ ive_ctl_set_me_params_ip_t s_me_params_ip; ++ ive_ctl_set_me_params_op_t s_me_params_op; ++ ++ s_me_params_ip.e_cmd = IVE_CMD_VIDEO_CTL; ++ s_me_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_ME_PARAMS; ++ ++ s_me_params_ip.u4_enable_fast_sad = mEnableFastSad; ++ s_me_params_ip.u4_enable_alt_ref = mEnableAltRef; ++ ++ s_me_params_ip.u4_enable_hpel = mHalfPelEnable; ++ s_me_params_ip.u4_enable_qpel = DEFAULT_QPEL; ++ s_me_params_ip.u4_me_speed_preset = DEFAULT_ME_SPEED; ++ s_me_params_ip.u4_srch_rng_x = DEFAULT_SRCH_RNG_X; ++ s_me_params_ip.u4_srch_rng_y = DEFAULT_SRCH_RNG_Y; ++ ++ s_me_params_ip.u4_timestamp_high = -1; ++ s_me_params_ip.u4_timestamp_low = -1; ++ ++ s_me_params_ip.u4_size = sizeof(ive_ctl_set_me_params_ip_t); ++ s_me_params_op.u4_size = sizeof(ive_ctl_set_me_params_op_t); ++ ++ status = ive_api_function(mCodecCtx, &s_me_params_ip, &s_me_params_op); ++ if (status != IV_SUCCESS) { ++ ALOGE("Unable to set me params = 0x%x\n", s_me_params_op.u4_error_code); ++ return OMX_ErrorUndefined; ++ } ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftAVC::setGopParams() { ++ IV_STATUS_T status; ++ ive_ctl_set_gop_params_ip_t s_gop_params_ip; ++ ive_ctl_set_gop_params_op_t s_gop_params_op; ++ ++ s_gop_params_ip.e_cmd = IVE_CMD_VIDEO_CTL; ++ s_gop_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_GOP_PARAMS; ++ ++ s_gop_params_ip.u4_i_frm_interval = mIInterval; ++ s_gop_params_ip.u4_idr_frm_interval = mIDRInterval; ++ ++ s_gop_params_ip.u4_timestamp_high = -1; ++ s_gop_params_ip.u4_timestamp_low = -1; ++ ++ s_gop_params_ip.u4_size = sizeof(ive_ctl_set_gop_params_ip_t); ++ s_gop_params_op.u4_size = sizeof(ive_ctl_set_gop_params_op_t); ++ ++ status = ive_api_function(mCodecCtx, &s_gop_params_ip, &s_gop_params_op); ++ if (status != IV_SUCCESS) { ++ ALOGE("Unable to set ME params = 0x%x\n", ++ s_gop_params_op.u4_error_code); ++ return OMX_ErrorUndefined; ++ } ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftAVC::setProfileParams() { ++ IV_STATUS_T status; ++ ive_ctl_set_profile_params_ip_t s_profile_params_ip; ++ ive_ctl_set_profile_params_op_t s_profile_params_op; ++ ++ s_profile_params_ip.e_cmd = IVE_CMD_VIDEO_CTL; ++ s_profile_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_PROFILE_PARAMS; ++ ++ s_profile_params_ip.e_profile = DEFAULT_EPROFILE; ++ s_profile_params_ip.u4_entropy_coding_mode = mEntropyMode; ++ s_profile_params_ip.u4_timestamp_high = -1; ++ s_profile_params_ip.u4_timestamp_low = -1; ++ ++ s_profile_params_ip.u4_size = sizeof(ive_ctl_set_profile_params_ip_t); ++ s_profile_params_op.u4_size = sizeof(ive_ctl_set_profile_params_op_t); ++ ++ status = ive_api_function(mCodecCtx, &s_profile_params_ip, &s_profile_params_op); ++ if (status != IV_SUCCESS) { ++ ALOGE("Unable to set profile params = 0x%x\n", ++ s_profile_params_op.u4_error_code); ++ return OMX_ErrorUndefined; ++ } ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftAVC::setDeblockParams() { ++ IV_STATUS_T status; ++ ive_ctl_set_deblock_params_ip_t s_deblock_params_ip; ++ ive_ctl_set_deblock_params_op_t s_deblock_params_op; ++ ++ s_deblock_params_ip.e_cmd = IVE_CMD_VIDEO_CTL; ++ s_deblock_params_ip.e_sub_cmd = IVE_CMD_CTL_SET_DEBLOCK_PARAMS; ++ ++ s_deblock_params_ip.u4_disable_deblock_level = mDisableDeblkLevel; ++ ++ s_deblock_params_ip.u4_timestamp_high = -1; ++ s_deblock_params_ip.u4_timestamp_low = -1; ++ ++ s_deblock_params_ip.u4_size = sizeof(ive_ctl_set_deblock_params_ip_t); ++ s_deblock_params_op.u4_size = sizeof(ive_ctl_set_deblock_params_op_t); ++ ++ status = ive_api_function(mCodecCtx, &s_deblock_params_ip, &s_deblock_params_op); ++ if (status != IV_SUCCESS) { ++ ALOGE("Unable to enable/disable deblock params = 0x%x\n", ++ s_deblock_params_op.u4_error_code); ++ return OMX_ErrorUndefined; ++ } ++ return OMX_ErrorNone; ++} ++ ++void SoftAVC::logVersion() { ++ ive_ctl_getversioninfo_ip_t s_ctl_ip; ++ ive_ctl_getversioninfo_op_t s_ctl_op; ++ UWORD8 au1_buf[512]; ++ IV_STATUS_T status; ++ ++ s_ctl_ip.e_cmd = IVE_CMD_VIDEO_CTL; ++ s_ctl_ip.e_sub_cmd = IVE_CMD_CTL_GETVERSION; ++ s_ctl_ip.u4_size = sizeof(ive_ctl_getversioninfo_ip_t); ++ s_ctl_op.u4_size = sizeof(ive_ctl_getversioninfo_op_t); ++ s_ctl_ip.pu1_version = au1_buf; ++ s_ctl_ip.u4_version_bufsize = sizeof(au1_buf); ++ ++ status = ive_api_function(mCodecCtx, (void *) &s_ctl_ip, (void *) &s_ctl_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGE("Error in getting version: 0x%x", s_ctl_op.u4_error_code); ++ } else { ++ ALOGV("Ittiam encoder version: %s", (char *)s_ctl_ip.pu1_version); ++ } ++ return; ++} ++ ++OMX_ERRORTYPE SoftAVC::initEncoder() { ++ IV_STATUS_T status; ++ WORD32 level; ++ uint32_t displaySizeY; ++ ++ CHECK(!mStarted); ++ ++ OMX_ERRORTYPE errType = OMX_ErrorNone; ++ ++ displaySizeY = mWidth * mHeight; ++ if (displaySizeY > (1920 * 1088)) { ++ level = 50; ++ } else if (displaySizeY > (1280 * 720)) { ++ level = 40; ++ } else if (displaySizeY > (720 * 576)) { ++ level = 31; ++ } else if (displaySizeY > (624 * 320)) { ++ level = 30; ++ } else if (displaySizeY > (352 * 288)) { ++ level = 21; ++ } else if (displaySizeY > (176 * 144)) { ++ level = 20; ++ } else { ++ level = 10; ++ } ++ mAVCEncLevel = MAX(level, mAVCEncLevel); ++ ++ mStride = mWidth; ++ ++ if (mInputDataIsMeta) { ++ for (size_t i = 0; i < MAX_CONVERSION_BUFFERS; i++) { ++ if (mConversionBuffers[i] != NULL) { ++ free(mConversionBuffers[i]); ++ mConversionBuffers[i] = 0; ++ } ++ ++ if (((uint64_t)mStride * mHeight) > ((uint64_t)INT32_MAX / 3)) { ++ ALOGE("Buffer size is too big."); ++ return OMX_ErrorUndefined; ++ } ++ mConversionBuffers[i] = (uint8_t *)malloc(mStride * mHeight * 3 / 2); ++ ++ if (mConversionBuffers[i] == NULL) { ++ ALOGE("Allocating conversion buffer failed."); ++ return OMX_ErrorUndefined; ++ } ++ ++ mConversionBuffersFree[i] = 1; ++ } ++ } ++ ++ switch (mColorFormat) { ++ case OMX_COLOR_FormatYUV420SemiPlanar: ++ mIvVideoColorFormat = IV_YUV_420SP_UV; ++ ALOGV("colorFormat YUV_420SP"); ++ break; ++ default: ++ case OMX_COLOR_FormatYUV420Planar: ++ mIvVideoColorFormat = IV_YUV_420P; ++ ALOGV("colorFormat YUV_420P"); ++ break; ++ } ++ ++ ALOGD("Params width %d height %d level %d colorFormat %d", mWidth, ++ mHeight, mAVCEncLevel, mIvVideoColorFormat); ++ ++ /* Getting Number of MemRecords */ ++ { ++ iv_num_mem_rec_ip_t s_num_mem_rec_ip; ++ iv_num_mem_rec_op_t s_num_mem_rec_op; ++ ++ s_num_mem_rec_ip.u4_size = sizeof(iv_num_mem_rec_ip_t); ++ s_num_mem_rec_op.u4_size = sizeof(iv_num_mem_rec_op_t); ++ ++ s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC; ++ ++ status = ive_api_function(0, &s_num_mem_rec_ip, &s_num_mem_rec_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGE("Get number of memory records failed = 0x%x\n", ++ s_num_mem_rec_op.u4_error_code); ++ return OMX_ErrorUndefined; ++ } ++ ++ mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec; ++ } ++ ++ /* Allocate array to hold memory records */ ++ if (mNumMemRecords > SIZE_MAX / sizeof(iv_mem_rec_t)) { ++ ALOGE("requested memory size is too big."); ++ return OMX_ErrorUndefined; ++ } ++ mMemRecords = (iv_mem_rec_t *)malloc(mNumMemRecords * sizeof(iv_mem_rec_t)); ++ if (NULL == mMemRecords) { ++ ALOGE("Unable to allocate memory for hold memory records: Size %zu", ++ mNumMemRecords * sizeof(iv_mem_rec_t)); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); ++ return OMX_ErrorUndefined; ++ } ++ ++ { ++ iv_mem_rec_t *ps_mem_rec; ++ ps_mem_rec = mMemRecords; ++ for (size_t i = 0; i < mNumMemRecords; i++) { ++ ps_mem_rec->u4_size = sizeof(iv_mem_rec_t); ++ ps_mem_rec->pv_base = NULL; ++ ps_mem_rec->u4_mem_size = 0; ++ ps_mem_rec->u4_mem_alignment = 0; ++ ps_mem_rec->e_mem_type = IV_NA_MEM_TYPE; ++ ++ ps_mem_rec++; ++ } ++ } ++ ++ /* Getting MemRecords Attributes */ ++ { ++ iv_fill_mem_rec_ip_t s_fill_mem_rec_ip; ++ iv_fill_mem_rec_op_t s_fill_mem_rec_op; ++ ++ s_fill_mem_rec_ip.u4_size = sizeof(iv_fill_mem_rec_ip_t); ++ s_fill_mem_rec_op.u4_size = sizeof(iv_fill_mem_rec_op_t); ++ ++ s_fill_mem_rec_ip.e_cmd = IV_CMD_FILL_NUM_MEM_REC; ++ s_fill_mem_rec_ip.ps_mem_rec = mMemRecords; ++ s_fill_mem_rec_ip.u4_num_mem_rec = mNumMemRecords; ++ s_fill_mem_rec_ip.u4_max_wd = mWidth; ++ s_fill_mem_rec_ip.u4_max_ht = mHeight; ++ s_fill_mem_rec_ip.u4_max_level = mAVCEncLevel; ++ s_fill_mem_rec_ip.e_color_format = DEFAULT_INP_COLOR_FORMAT; ++ s_fill_mem_rec_ip.u4_max_ref_cnt = DEFAULT_MAX_REF_FRM; ++ s_fill_mem_rec_ip.u4_max_reorder_cnt = DEFAULT_MAX_REORDER_FRM; ++ s_fill_mem_rec_ip.u4_max_srch_rng_x = DEFAULT_MAX_SRCH_RANGE_X; ++ s_fill_mem_rec_ip.u4_max_srch_rng_y = DEFAULT_MAX_SRCH_RANGE_Y; ++ ++ status = ive_api_function(0, &s_fill_mem_rec_ip, &s_fill_mem_rec_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGE("Fill memory records failed = 0x%x\n", ++ s_fill_mem_rec_op.u4_error_code); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); ++ return OMX_ErrorUndefined; ++ } ++ } ++ ++ /* Allocating Memory for Mem Records */ ++ { ++ WORD32 total_size; ++ iv_mem_rec_t *ps_mem_rec; ++ total_size = 0; ++ ps_mem_rec = mMemRecords; ++ ++ for (size_t i = 0; i < mNumMemRecords; i++) { ++ ps_mem_rec->pv_base = ive_aligned_malloc( ++ ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size); ++ if (ps_mem_rec->pv_base == NULL) { ++ ALOGE("Allocation failure for mem record id %zu size %u\n", i, ++ ps_mem_rec->u4_mem_size); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); ++ return OMX_ErrorUndefined; ++ ++ } ++ total_size += ps_mem_rec->u4_mem_size; ++ ++ ps_mem_rec++; ++ } ++ } ++ ++ /* Codec Instance Creation */ ++ { ++ ive_init_ip_t s_init_ip; ++ ive_init_op_t s_init_op; ++ ++ mCodecCtx = (iv_obj_t *)mMemRecords[0].pv_base; ++ mCodecCtx->u4_size = sizeof(iv_obj_t); ++ mCodecCtx->pv_fxns = (void *)ive_api_function; ++ ++ s_init_ip.u4_size = sizeof(ive_init_ip_t); ++ s_init_op.u4_size = sizeof(ive_init_op_t); ++ ++ s_init_ip.e_cmd = IV_CMD_INIT; ++ s_init_ip.u4_num_mem_rec = mNumMemRecords; ++ s_init_ip.ps_mem_rec = mMemRecords; ++ s_init_ip.u4_max_wd = mWidth; ++ s_init_ip.u4_max_ht = mHeight; ++ s_init_ip.u4_max_ref_cnt = DEFAULT_MAX_REF_FRM; ++ s_init_ip.u4_max_reorder_cnt = DEFAULT_MAX_REORDER_FRM; ++ s_init_ip.u4_max_level = mAVCEncLevel; ++ s_init_ip.e_inp_color_fmt = mIvVideoColorFormat; ++ ++ if (mReconEnable || mPSNREnable) { ++ s_init_ip.u4_enable_recon = 1; ++ } else { ++ s_init_ip.u4_enable_recon = 0; ++ } ++ s_init_ip.e_recon_color_fmt = DEFAULT_RECON_COLOR_FORMAT; ++ s_init_ip.e_rc_mode = DEFAULT_RC_MODE; ++ s_init_ip.u4_max_framerate = DEFAULT_MAX_FRAMERATE; ++ s_init_ip.u4_max_bitrate = DEFAULT_MAX_BITRATE; ++ s_init_ip.u4_num_bframes = mBframes; ++ s_init_ip.e_content_type = IV_PROGRESSIVE; ++ s_init_ip.u4_max_srch_rng_x = DEFAULT_MAX_SRCH_RANGE_X; ++ s_init_ip.u4_max_srch_rng_y = DEFAULT_MAX_SRCH_RANGE_Y; ++ s_init_ip.e_slice_mode = mSliceMode; ++ s_init_ip.u4_slice_param = mSliceParam; ++ s_init_ip.e_arch = mArch; ++ s_init_ip.e_soc = DEFAULT_SOC; ++ ++ status = ive_api_function(mCodecCtx, &s_init_ip, &s_init_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGE("Init memory records failed = 0x%x\n", ++ s_init_op.u4_error_code); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0 /* arg2 */, NULL /* data */); ++ return OMX_ErrorUndefined; ++ } ++ } ++ ++ /* Get Codec Version */ ++ logVersion(); ++ ++ /* set processor details */ ++ setNumCores(); ++ ++ /* Video control Set Frame dimensions */ ++ setDimensions(); ++ ++ /* Video control Set Frame rates */ ++ setFrameRate(); ++ ++ /* Video control Set IPE Params */ ++ setIpeParams(); ++ ++ /* Video control Set Bitrate */ ++ setBitRate(); ++ ++ /* Video control Set QP */ ++ setQp(); ++ ++ /* Video control Set AIR params */ ++ setAirParams(); ++ ++ /* Video control Set VBV params */ ++ setVbvParams(); ++ ++ /* Video control Set Motion estimation params */ ++ setMeParams(); ++ ++ /* Video control Set GOP params */ ++ setGopParams(); ++ ++ /* Video control Set Deblock params */ ++ setDeblockParams(); ++ ++ /* Video control Set Profile params */ ++ setProfileParams(); ++ ++ /* Video control Set in Encode header mode */ ++ setEncMode(IVE_ENC_MODE_HEADER); ++ ++ ALOGV("init_codec successfull"); ++ ++ mSpsPpsHeaderReceived = false; ++ mStarted = true; ++ ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftAVC::releaseEncoder() { ++ IV_STATUS_T status = IV_SUCCESS; ++ iv_retrieve_mem_rec_ip_t s_retrieve_mem_ip; ++ iv_retrieve_mem_rec_op_t s_retrieve_mem_op; ++ iv_mem_rec_t *ps_mem_rec; ++ ++ if (!mStarted) { ++ return OMX_ErrorNone; ++ } ++ ++ s_retrieve_mem_ip.u4_size = sizeof(iv_retrieve_mem_rec_ip_t); ++ s_retrieve_mem_op.u4_size = sizeof(iv_retrieve_mem_rec_op_t); ++ s_retrieve_mem_ip.e_cmd = IV_CMD_RETRIEVE_MEMREC; ++ s_retrieve_mem_ip.ps_mem_rec = mMemRecords; ++ ++ status = ive_api_function(mCodecCtx, &s_retrieve_mem_ip, &s_retrieve_mem_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGE("Unable to retrieve memory records = 0x%x\n", ++ s_retrieve_mem_op.u4_error_code); ++ return OMX_ErrorUndefined; ++ } ++ ++ /* Free memory records */ ++ ps_mem_rec = mMemRecords; ++ for (size_t i = 0; i < s_retrieve_mem_op.u4_num_mem_rec_filled; i++) { ++ ive_aligned_free(ps_mem_rec->pv_base); ++ ps_mem_rec++; ++ } ++ ++ free(mMemRecords); ++ ++ for (size_t i = 0; i < MAX_CONVERSION_BUFFERS; i++) { ++ if (mConversionBuffers[i]) { ++ free(mConversionBuffers[i]); ++ mConversionBuffers[i] = NULL; ++ } ++ } ++ ++ // clear other pointers into the space being free()d ++ mCodecCtx = NULL; ++ ++ mStarted = false; ++ ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftAVC::internalGetParameter(OMX_INDEXTYPE index, OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamVideoBitrate: ++ { ++ OMX_VIDEO_PARAM_BITRATETYPE *bitRate = ++ (OMX_VIDEO_PARAM_BITRATETYPE *)params; ++ ++ if (!isValidOMXParam(bitRate)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (bitRate->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ bitRate->eControlRate = OMX_Video_ControlRateVariable; ++ bitRate->nTargetBitrate = mBitrate; ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamVideoAvc: ++ { ++ OMX_VIDEO_PARAM_AVCTYPE *avcParams = (OMX_VIDEO_PARAM_AVCTYPE *)params; ++ ++ if (!isValidOMXParam(avcParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (avcParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ OMX_VIDEO_AVCLEVELTYPE omxLevel = OMX_VIDEO_AVCLevel41; ++ if (OMX_ErrorNone ++ != ConvertAvcSpecLevelToOmxAvcLevel(mAVCEncLevel, &omxLevel)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ // TODO: maintain profile ++ avcParams->eProfile = (OMX_VIDEO_AVCPROFILETYPE)OMX_VIDEO_AVCProfileConstrainedBaseline; ++ avcParams->eLevel = omxLevel; ++ avcParams->nRefFrames = 1; ++ avcParams->bUseHadamard = OMX_TRUE; ++ avcParams->nAllowedPictureTypes = (OMX_VIDEO_PictureTypeI ++ | OMX_VIDEO_PictureTypeP | OMX_VIDEO_PictureTypeB); ++ avcParams->nRefIdx10ActiveMinus1 = 0; ++ avcParams->nRefIdx11ActiveMinus1 = 0; ++ avcParams->bWeightedPPrediction = OMX_FALSE; ++ avcParams->bconstIpred = OMX_FALSE; ++ avcParams->bDirect8x8Inference = OMX_FALSE; ++ avcParams->bDirectSpatialTemporal = OMX_FALSE; ++ avcParams->nCabacInitIdc = 0; ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SoftVideoEncoderOMXComponent::internalGetParameter(index, params); ++ } ++} ++ ++OMX_ERRORTYPE SoftAVC::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) { ++ int32_t indexFull = index; ++ ++ switch (indexFull) { ++ case OMX_IndexParamVideoBitrate: ++ { ++ OMX_VIDEO_PARAM_BITRATETYPE *bitRate = ++ (OMX_VIDEO_PARAM_BITRATETYPE *)params; ++ ++ if (!isValidOMXParam(bitRate)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ return internalSetBitrateParams(bitRate); ++ } ++ ++ case OMX_IndexParamVideoAvc: ++ { ++ OMX_VIDEO_PARAM_AVCTYPE *avcType = (OMX_VIDEO_PARAM_AVCTYPE *)params; ++ ++ if (!isValidOMXParam(avcType)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (avcType->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ mEntropyMode = 0; ++ ++ if (OMX_TRUE == avcType->bEntropyCodingCABAC) ++ mEntropyMode = 1; ++ ++ if ((avcType->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) && ++ avcType->nPFrames) { ++ mBframes = avcType->nBFrames; ++ } ++ ++ mIInterval = (avcType->nPFrames + 1) * (avcType->nBFrames + 1); ++ mConstrainedIntraFlag = avcType->bconstIpred; ++ ++ if (OMX_VIDEO_AVCLoopFilterDisable == avcType->eLoopFilterMode) ++ mDisableDeblkLevel = 4; ++ ++ if (avcType->nRefFrames != 1 ++ || avcType->bUseHadamard != OMX_TRUE ++ || avcType->nRefIdx10ActiveMinus1 != 0 ++ || avcType->nRefIdx11ActiveMinus1 != 0 ++ || avcType->bWeightedPPrediction != OMX_FALSE ++ || avcType->bDirect8x8Inference != OMX_FALSE ++ || avcType->bDirectSpatialTemporal != OMX_FALSE ++ || avcType->nCabacInitIdc != 0) { ++ // OMX does not allow a way to signal what values are wrong, so it's ++ // best for components to just do best effort in supporting these values ++ ALOGV("ignoring unsupported settings"); ++ } ++ ++ if (OK != ConvertOmxAvcLevelToAvcSpecLevel(avcType->eLevel, &mAVCEncLevel)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SoftVideoEncoderOMXComponent::internalSetParameter(index, params); ++ } ++} ++ ++OMX_ERRORTYPE SoftAVC::getConfig( ++ OMX_INDEXTYPE index, OMX_PTR _params) { ++ switch ((int)index) { ++ case OMX_IndexConfigAndroidIntraRefresh: ++ { ++ OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *intraRefreshParams = ++ (OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *)_params; ++ ++ if (!isValidOMXParam(intraRefreshParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (intraRefreshParams->nPortIndex != kOutputPortIndex) { ++ return OMX_ErrorUndefined; ++ } ++ ++ intraRefreshParams->nRefreshPeriod = ++ (mAIRMode == IVE_AIR_MODE_NONE) ? 0 : mAIRRefreshPeriod; ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SoftVideoEncoderOMXComponent::getConfig(index, _params); ++ } ++} ++ ++OMX_ERRORTYPE SoftAVC::internalSetConfig( ++ OMX_INDEXTYPE index, const OMX_PTR _params, bool *frameConfig) { ++ switch ((int)index) { ++ case OMX_IndexConfigVideoIntraVOPRefresh: ++ { ++ OMX_CONFIG_INTRAREFRESHVOPTYPE *params = ++ (OMX_CONFIG_INTRAREFRESHVOPTYPE *)_params; ++ ++ if (!isValidOMXParam(params)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (params->nPortIndex != kOutputPortIndex) { ++ return OMX_ErrorBadPortIndex; ++ } ++ ++ if (params->IntraRefreshVOP) { ++ mUpdateFlag |= kRequestKeyFrame; ++ } ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexConfigVideoBitrate: ++ { ++ OMX_VIDEO_CONFIG_BITRATETYPE *params = ++ (OMX_VIDEO_CONFIG_BITRATETYPE *)_params; ++ ++ if (!isValidOMXParam(params)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (params->nPortIndex != kOutputPortIndex) { ++ return OMX_ErrorBadPortIndex; ++ } ++ ++ if (mBitrate != params->nEncodeBitrate) { ++ mBitrate = params->nEncodeBitrate; ++ mUpdateFlag |= kUpdateBitrate; ++ } ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexConfigAndroidIntraRefresh: ++ { ++ const OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *intraRefreshParams = ++ (const OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *)_params; ++ ++ if (!isValidOMXParam(intraRefreshParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (intraRefreshParams->nPortIndex != kOutputPortIndex) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (intraRefreshParams->nRefreshPeriod == 0) { ++ mAIRMode = IVE_AIR_MODE_NONE; ++ mAIRRefreshPeriod = 0; ++ } else if (intraRefreshParams->nRefreshPeriod > 0) { ++ mAIRMode = IVE_AIR_MODE_CYCLIC; ++ mAIRRefreshPeriod = intraRefreshParams->nRefreshPeriod; ++ } ++ mUpdateFlag |= kUpdateAIRMode; ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalSetConfig(index, _params, frameConfig); ++ } ++} ++ ++OMX_ERRORTYPE SoftAVC::internalSetBitrateParams( ++ const OMX_VIDEO_PARAM_BITRATETYPE *bitrate) { ++ if (bitrate->nPortIndex != kOutputPortIndex) { ++ return OMX_ErrorUnsupportedIndex; ++ } ++ ++ mBitrate = bitrate->nTargetBitrate; ++ mUpdateFlag |= kUpdateBitrate; ++ ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftAVC::setEncodeArgs( ++ ive_video_encode_ip_t *ps_encode_ip, ++ ive_video_encode_op_t *ps_encode_op, ++ OMX_BUFFERHEADERTYPE *inputBufferHeader, ++ OMX_BUFFERHEADERTYPE *outputBufferHeader) { ++ iv_raw_buf_t *ps_inp_raw_buf; ++ const uint8_t *source; ++ UWORD8 *pu1_buf; ++ ++ ps_inp_raw_buf = &ps_encode_ip->s_inp_buf; ++ ps_encode_ip->s_out_buf.pv_buf = outputBufferHeader->pBuffer; ++ ps_encode_ip->s_out_buf.u4_bytes = 0; ++ ps_encode_ip->s_out_buf.u4_bufsize = outputBufferHeader->nAllocLen; ++ ps_encode_ip->u4_size = sizeof(ive_video_encode_ip_t); ++ ps_encode_op->u4_size = sizeof(ive_video_encode_op_t); ++ ++ ps_encode_ip->e_cmd = IVE_CMD_VIDEO_ENCODE; ++ ps_encode_ip->pv_bufs = NULL; ++ ps_encode_ip->pv_mb_info = NULL; ++ ps_encode_ip->pv_pic_info = NULL; ++ ps_encode_ip->u4_mb_info_type = 0; ++ ps_encode_ip->u4_pic_info_type = 0; ++ ps_encode_op->s_out_buf.pv_buf = NULL; ++ ++ /* Initialize color formats */ ++ ps_inp_raw_buf->e_color_fmt = mIvVideoColorFormat; ++ source = NULL; ++ if ((inputBufferHeader != NULL) && inputBufferHeader->nFilledLen) { ++ OMX_ERRORTYPE error = validateInputBuffer(inputBufferHeader); ++ if (error != OMX_ErrorNone) { ++ ALOGE("b/69065651"); ++ android_errorWriteLog(0x534e4554, "69065651"); ++ return error; ++ } ++ source = inputBufferHeader->pBuffer + inputBufferHeader->nOffset; ++ ++ if (mInputDataIsMeta) { ++ uint8_t *conversionBuffer = NULL; ++ for (size_t i = 0; i < MAX_CONVERSION_BUFFERS; i++) { ++ if (mConversionBuffersFree[i]) { ++ mConversionBuffersFree[i] = 0; ++ conversionBuffer = mConversionBuffers[i]; ++ break; ++ } ++ } ++ ++ if (NULL == conversionBuffer) { ++ ALOGE("No free buffers to hold conversion data"); ++ return OMX_ErrorUndefined; ++ } ++ ++ source = extractGraphicBuffer( ++ conversionBuffer, (mWidth * mHeight * 3 / 2), source, ++ inputBufferHeader->nFilledLen, mWidth, mHeight); ++ ++ if (source == NULL) { ++ ALOGE("Error in extractGraphicBuffer"); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); ++ return OMX_ErrorUndefined; ++ } ++ } ++ ps_encode_ip->u4_is_last = 0; ++ ps_encode_ip->u4_timestamp_high = (inputBufferHeader->nTimeStamp) >> 32; ++ ps_encode_ip->u4_timestamp_low = (inputBufferHeader->nTimeStamp) & 0xFFFFFFFF; ++ } ++ else { ++ if (mSawInputEOS){ ++ ps_encode_ip->u4_is_last = 1; ++ } ++ memset(ps_inp_raw_buf, 0, sizeof(iv_raw_buf_t)); ++ ps_inp_raw_buf->e_color_fmt = mIvVideoColorFormat; ++ ps_inp_raw_buf->u4_size = sizeof(iv_raw_buf_t); ++ return OMX_ErrorNone; ++ } ++ ++ pu1_buf = (UWORD8 *)source; ++ switch (mIvVideoColorFormat) { ++ case IV_YUV_420P: ++ { ++ ps_inp_raw_buf->apv_bufs[0] = pu1_buf; ++ pu1_buf += (mStride) * mHeight; ++ ps_inp_raw_buf->apv_bufs[1] = pu1_buf; ++ pu1_buf += (mStride / 2) * mHeight / 2; ++ ps_inp_raw_buf->apv_bufs[2] = pu1_buf; ++ ++ ps_inp_raw_buf->au4_wd[0] = mWidth; ++ ps_inp_raw_buf->au4_wd[1] = mWidth / 2; ++ ps_inp_raw_buf->au4_wd[2] = mWidth / 2; ++ ++ ps_inp_raw_buf->au4_ht[0] = mHeight; ++ ps_inp_raw_buf->au4_ht[1] = mHeight / 2; ++ ps_inp_raw_buf->au4_ht[2] = mHeight / 2; ++ ++ ps_inp_raw_buf->au4_strd[0] = mStride; ++ ps_inp_raw_buf->au4_strd[1] = (mStride / 2); ++ ps_inp_raw_buf->au4_strd[2] = (mStride / 2); ++ break; ++ } ++ ++ case IV_YUV_422ILE: ++ { ++ ps_inp_raw_buf->apv_bufs[0] = pu1_buf; ++ ps_inp_raw_buf->au4_wd[0] = mWidth * 2; ++ ps_inp_raw_buf->au4_ht[0] = mHeight; ++ ps_inp_raw_buf->au4_strd[0] = mStride * 2; ++ break; ++ } ++ ++ case IV_YUV_420SP_UV: ++ case IV_YUV_420SP_VU: ++ default: ++ { ++ ps_inp_raw_buf->apv_bufs[0] = pu1_buf; ++ pu1_buf += (mStride) * mHeight; ++ ps_inp_raw_buf->apv_bufs[1] = pu1_buf; ++ ++ ps_inp_raw_buf->au4_wd[0] = mWidth; ++ ps_inp_raw_buf->au4_wd[1] = mWidth; ++ ++ ps_inp_raw_buf->au4_ht[0] = mHeight; ++ ps_inp_raw_buf->au4_ht[1] = mHeight / 2; ++ ++ ps_inp_raw_buf->au4_strd[0] = mStride; ++ ps_inp_raw_buf->au4_strd[1] = mStride; ++ break; ++ } ++ } ++ return OMX_ErrorNone; ++} ++ ++void SoftAVC::onQueueFilled(OMX_U32 portIndex) { ++ IV_STATUS_T status; ++ WORD32 timeDelay, timeTaken; ++ ++ UNUSED(portIndex); ++ ++ // Initialize encoder if not already initialized ++ if (mCodecCtx == NULL) { ++ if (OMX_ErrorNone != initEncoder()) { ++ ALOGE("Failed to initialize encoder"); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0 /* arg2 */, NULL /* data */); ++ return; ++ } ++ } ++ if (mSignalledError) { ++ return; ++ } ++ ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ ++ while (!mSawOutputEOS && !outQueue.empty()) { ++ ++ OMX_ERRORTYPE error; ++ ive_video_encode_ip_t s_encode_ip; ++ ive_video_encode_op_t s_encode_op; ++ BufferInfo *outputBufferInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outputBufferHeader = outputBufferInfo->mHeader; ++ ++ BufferInfo *inputBufferInfo; ++ OMX_BUFFERHEADERTYPE *inputBufferHeader; ++ ++ if (mSawInputEOS) { ++ inputBufferHeader = NULL; ++ inputBufferInfo = NULL; ++ } else if (!inQueue.empty()) { ++ inputBufferInfo = *inQueue.begin(); ++ inputBufferHeader = inputBufferInfo->mHeader; ++ } else { ++ return; ++ } ++ ++ outputBufferHeader->nTimeStamp = 0; ++ outputBufferHeader->nFlags = 0; ++ outputBufferHeader->nOffset = 0; ++ outputBufferHeader->nFilledLen = 0; ++ outputBufferHeader->nOffset = 0; ++ ++ if (inputBufferHeader != NULL) { ++ outputBufferHeader->nFlags = inputBufferHeader->nFlags; ++ } ++ ++ uint8_t *outPtr = (uint8_t *)outputBufferHeader->pBuffer; ++ ++ if (!mSpsPpsHeaderReceived) { ++ error = setEncodeArgs(&s_encode_ip, &s_encode_op, NULL, outputBufferHeader); ++ if (error != OMX_ErrorNone) { ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); ++ return; ++ } ++ status = ive_api_function(mCodecCtx, &s_encode_ip, &s_encode_op); ++ ++ if (IV_SUCCESS != status) { ++ ALOGE("Encode Frame failed = 0x%x\n", ++ s_encode_op.u4_error_code); ++ } else { ++ ALOGV("Bytes Generated in header %d\n", ++ s_encode_op.s_out_buf.u4_bytes); ++ } ++ ++ mSpsPpsHeaderReceived = true; ++ ++ outputBufferHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG; ++ outputBufferHeader->nFilledLen = s_encode_op.s_out_buf.u4_bytes; ++ if (inputBufferHeader != NULL) { ++ outputBufferHeader->nTimeStamp = inputBufferHeader->nTimeStamp; ++ } ++ ++ outQueue.erase(outQueue.begin()); ++ outputBufferInfo->mOwnedByUs = false; ++ ++ DUMP_TO_FILE( ++ mOutFile, outputBufferHeader->pBuffer, ++ outputBufferHeader->nFilledLen); ++ notifyFillBufferDone(outputBufferHeader); ++ ++ setEncMode(IVE_ENC_MODE_PICTURE); ++ return; ++ } ++ ++ if (mUpdateFlag) { ++ if (mUpdateFlag & kUpdateBitrate) { ++ setBitRate(); ++ } ++ if (mUpdateFlag & kRequestKeyFrame) { ++ setFrameType(IV_IDR_FRAME); ++ } ++ if (mUpdateFlag & kUpdateAIRMode) { ++ setAirParams(); ++ notify(OMX_EventPortSettingsChanged, kOutputPortIndex, ++ OMX_IndexConfigAndroidIntraRefresh, NULL); ++ } ++ mUpdateFlag = 0; ++ } ++ ++ if ((inputBufferHeader != NULL) ++ && (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS)) { ++ mSawInputEOS = true; ++ } ++ ++ /* In normal mode, store inputBufferInfo and this will be returned ++ when encoder consumes this input */ ++ if (!mInputDataIsMeta && (inputBufferInfo != NULL)) { ++ for (size_t i = 0; i < MAX_INPUT_BUFFER_HEADERS; i++) { ++ if (NULL == mInputBufferInfo[i]) { ++ mInputBufferInfo[i] = inputBufferInfo; ++ break; ++ } ++ } ++ } ++ error = setEncodeArgs( ++ &s_encode_ip, &s_encode_op, inputBufferHeader, outputBufferHeader); ++ ++ if (error != OMX_ErrorNone) { ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); ++ return; ++ } ++ ++ DUMP_TO_FILE( ++ mInFile, s_encode_ip.s_inp_buf.apv_bufs[0], ++ (mHeight * mStride * 3 / 2)); ++ ++ GETTIME(&mTimeStart, NULL); ++ /* Compute time elapsed between end of previous decode() ++ * to start of current decode() */ ++ TIME_DIFF(mTimeEnd, mTimeStart, timeDelay); ++ status = ive_api_function(mCodecCtx, &s_encode_ip, &s_encode_op); ++ ++ if (IV_SUCCESS != status) { ++ ALOGE("Encode Frame failed = 0x%x\n", ++ s_encode_op.u4_error_code); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); ++ return; ++ } ++ ++ GETTIME(&mTimeEnd, NULL); ++ /* Compute time taken for decode() */ ++ TIME_DIFF(mTimeStart, mTimeEnd, timeTaken); ++ ++ ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, ++ s_encode_op.s_out_buf.u4_bytes); ++ ++ /* In encoder frees up an input buffer, mark it as free */ ++ if (s_encode_op.s_inp_buf.apv_bufs[0] != NULL) { ++ if (mInputDataIsMeta) { ++ for (size_t i = 0; i < MAX_CONVERSION_BUFFERS; i++) { ++ if (mConversionBuffers[i] == s_encode_op.s_inp_buf.apv_bufs[0]) { ++ mConversionBuffersFree[i] = 1; ++ break; ++ } ++ } ++ } else { ++ /* In normal mode, call EBD on inBuffeHeader that is freed by the codec */ ++ for (size_t i = 0; i < MAX_INPUT_BUFFER_HEADERS; i++) { ++ uint8_t *buf = NULL; ++ OMX_BUFFERHEADERTYPE *bufHdr = NULL; ++ if (mInputBufferInfo[i] != NULL) { ++ bufHdr = mInputBufferInfo[i]->mHeader; ++ buf = bufHdr->pBuffer + bufHdr->nOffset; ++ } ++ if (s_encode_op.s_inp_buf.apv_bufs[0] == buf) { ++ mInputBufferInfo[i]->mOwnedByUs = false; ++ notifyEmptyBufferDone(bufHdr); ++ mInputBufferInfo[i] = NULL; ++ break; ++ } ++ } ++ } ++ } ++ ++ outputBufferHeader->nFilledLen = s_encode_op.s_out_buf.u4_bytes; ++ ++ if (IV_IDR_FRAME == s_encode_op.u4_encoded_frame_type) { ++ outputBufferHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME; ++ } ++ ++ if (inputBufferHeader != NULL) { ++ inQueue.erase(inQueue.begin()); ++ ++ /* If in meta data, call EBD on input */ ++ /* In case of normal mode, EBD will be done once encoder ++ releases the input buffer */ ++ if (mInputDataIsMeta) { ++ inputBufferInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inputBufferHeader); ++ } ++ } ++ ++ if (s_encode_op.u4_is_last) { ++ outputBufferHeader->nFlags |= OMX_BUFFERFLAG_EOS; ++ mSawOutputEOS = true; ++ } else { ++ outputBufferHeader->nFlags &= ~OMX_BUFFERFLAG_EOS; ++ } ++ ++ if (outputBufferHeader->nFilledLen || s_encode_op.u4_is_last) { ++ outputBufferHeader->nTimeStamp = s_encode_op.u4_timestamp_high; ++ outputBufferHeader->nTimeStamp <<= 32; ++ outputBufferHeader->nTimeStamp |= s_encode_op.u4_timestamp_low; ++ outputBufferInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ DUMP_TO_FILE(mOutFile, outputBufferHeader->pBuffer, ++ outputBufferHeader->nFilledLen); ++ notifyFillBufferDone(outputBufferHeader); ++ } ++ ++ if (s_encode_op.u4_is_last == 1) { ++ return; ++ } ++ } ++ return; ++} ++ ++void SoftAVC::onReset() { ++ SoftVideoEncoderOMXComponent::onReset(); ++ ++ if (releaseEncoder() != OMX_ErrorNone) { ++ ALOGW("releaseEncoder failed"); ++ } ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ return new android::SoftAVC(name, callbacks, appData, component); ++} +diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.h b/media/libstagefright/codecs/avcenc/SoftAVCEnc.h +new file mode 100644 +index 0000000..6d2e084 +--- /dev/null ++++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.h +@@ -0,0 +1,317 @@ ++/* ++ * Copyright 2012 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 __SOFT_AVC_ENC_H__ ++#define __SOFT_AVC_ENC_H__ ++ ++ ++#include ++#include ++ ++#include ++ ++namespace android { ++ ++#define MAX_INPUT_BUFFER_HEADERS 4 ++#define MAX_CONVERSION_BUFFERS 4 ++#define CODEC_MAX_CORES 4 ++#define LEN_STATUS_BUFFER (10 * 1024) ++#define MAX_VBV_BUFF_SIZE (120 * 16384) ++#define MAX_NUM_IO_BUFS 3 ++ ++#define DEFAULT_MAX_REF_FRM 2 ++#define DEFAULT_MAX_REORDER_FRM 0 ++#define DEFAULT_QP_MIN 10 ++#define DEFAULT_QP_MAX 40 ++#define DEFAULT_MAX_BITRATE 240000000 ++#define DEFAULT_MAX_SRCH_RANGE_X 256 ++#define DEFAULT_MAX_SRCH_RANGE_Y 256 ++#define DEFAULT_MAX_FRAMERATE 120000 ++#define DEFAULT_NUM_CORES 1 ++#define DEFAULT_NUM_CORES_PRE_ENC 0 ++#define DEFAULT_FPS 30 ++#define DEFAULT_ENC_SPEED IVE_NORMAL ++ ++#define DEFAULT_MEM_REC_CNT 0 ++#define DEFAULT_RECON_ENABLE 0 ++#define DEFAULT_CHKSUM_ENABLE 0 ++#define DEFAULT_START_FRM 0 ++#define DEFAULT_NUM_FRMS 0xFFFFFFFF ++#define DEFAULT_INP_COLOR_FORMAT IV_YUV_420SP_VU ++#define DEFAULT_RECON_COLOR_FORMAT IV_YUV_420P ++#define DEFAULT_LOOPBACK 0 ++#define DEFAULT_SRC_FRAME_RATE 30 ++#define DEFAULT_TGT_FRAME_RATE 30 ++#define DEFAULT_MAX_WD 1920 ++#define DEFAULT_MAX_HT 1920 ++#define DEFAULT_MAX_LEVEL 41 ++#define DEFAULT_STRIDE 0 ++#define DEFAULT_WD 1280 ++#define DEFAULT_HT 720 ++#define DEFAULT_PSNR_ENABLE 0 ++#define DEFAULT_ME_SPEED 100 ++#define DEFAULT_ENABLE_FAST_SAD 0 ++#define DEFAULT_ENABLE_ALT_REF 0 ++#define DEFAULT_RC_MODE IVE_RC_STORAGE ++#define DEFAULT_BITRATE 6000000 ++#define DEFAULT_I_QP 22 ++#define DEFAULT_I_QP_MAX DEFAULT_QP_MAX ++#define DEFAULT_I_QP_MIN DEFAULT_QP_MIN ++#define DEFAULT_P_QP 28 ++#define DEFAULT_P_QP_MAX DEFAULT_QP_MAX ++#define DEFAULT_P_QP_MIN DEFAULT_QP_MIN ++#define DEFAULT_B_QP 22 ++#define DEFAULT_B_QP_MAX DEFAULT_QP_MAX ++#define DEFAULT_B_QP_MIN DEFAULT_QP_MIN ++#define DEFAULT_AIR IVE_AIR_MODE_NONE ++#define DEFAULT_AIR_REFRESH_PERIOD 30 ++#define DEFAULT_SRCH_RNG_X 64 ++#define DEFAULT_SRCH_RNG_Y 48 ++#define DEFAULT_I_INTERVAL 30 ++#define DEFAULT_IDR_INTERVAL 1000 ++#define DEFAULT_B_FRAMES 0 ++#define DEFAULT_DISABLE_DEBLK_LEVEL 0 ++#define DEFAULT_HPEL 1 ++#define DEFAULT_QPEL 1 ++#define DEFAULT_I4 1 ++#define DEFAULT_EPROFILE IV_PROFILE_BASE ++#define DEFAULT_ENTROPY_MODE 0 ++#define DEFAULT_SLICE_MODE IVE_SLICE_MODE_NONE ++#define DEFAULT_SLICE_PARAM 256 ++#define DEFAULT_ARCH ARCH_ARM_A9Q ++#define DEFAULT_SOC SOC_GENERIC ++#define DEFAULT_INTRA4x4 0 ++#define STRLENGTH 500 ++#define DEFAULT_CONSTRAINED_INTRA 0 ++ ++#define MIN(a, b) ((a) < (b))? (a) : (b) ++#define MAX(a, b) ((a) > (b))? (a) : (b) ++#define ALIGN16(x) ((((x) + 15) >> 4) << 4) ++#define ALIGN128(x) ((((x) + 127) >> 7) << 7) ++#define ALIGN4096(x) ((((x) + 4095) >> 12) << 12) ++ ++/** Used to remove warnings about unused parameters */ ++#define UNUSED(x) ((void)(x)) ++ ++/** Get time */ ++#define GETTIME(a, b) gettimeofday(a, b); ++ ++/** Compute difference between start and end */ ++#define TIME_DIFF(start, end, diff) \ ++ diff = (((end).tv_sec - (start).tv_sec) * 1000000) + \ ++ ((end).tv_usec - (start).tv_usec); ++ ++#define ive_aligned_malloc(alignment, size) memalign(alignment, size) ++#define ive_aligned_free(buf) free(buf) ++ ++struct SoftAVC : public SoftVideoEncoderOMXComponent { ++ SoftAVC( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++ // Override SimpleSoftOMXComponent methods ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params); ++ ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ ++protected: ++ virtual ~SoftAVC(); ++ ++ virtual void onReset(); ++ ++private: ++ enum { ++ kNumBuffers = 2, ++ }; ++ ++ enum { ++ kUpdateBitrate = 1 << 0, ++ kRequestKeyFrame = 1 << 1, ++ kUpdateAIRMode = 1 << 2, ++ }; ++ ++ // OMX input buffer's timestamp and flags ++ typedef struct { ++ int64_t mTimeUs; ++ int32_t mFlags; ++ } InputBufferInfo; ++ ++ int32_t mStride; ++ ++ struct timeval mTimeStart; // Time at the start of decode() ++ struct timeval mTimeEnd; // Time at the end of decode() ++ ++ int mUpdateFlag; ++ ++#ifdef FILE_DUMP_ENABLE ++ char mInFile[200]; ++ char mOutFile[200]; ++#endif /* FILE_DUMP_ENABLE */ ++ ++ IV_COLOR_FORMAT_T mIvVideoColorFormat; ++ ++ IV_PROFILE_T mAVCEncProfile; ++ WORD32 mAVCEncLevel; ++ bool mStarted; ++ bool mSpsPpsHeaderReceived; ++ ++ bool mSawInputEOS; ++ bool mSawOutputEOS; ++ bool mSignalledError; ++ bool mIntra4x4; ++ bool mEnableFastSad; ++ bool mEnableAltRef; ++ bool mReconEnable; ++ bool mPSNREnable; ++ bool mEntropyMode; ++ bool mConstrainedIntraFlag; ++ IVE_SPEED_CONFIG mEncSpeed; ++ ++ uint8_t *mConversionBuffers[MAX_CONVERSION_BUFFERS]; ++ bool mConversionBuffersFree[MAX_CONVERSION_BUFFERS]; ++ BufferInfo *mInputBufferInfo[MAX_INPUT_BUFFER_HEADERS]; ++ iv_obj_t *mCodecCtx; // Codec context ++ iv_mem_rec_t *mMemRecords; // Memory records requested by the codec ++ size_t mNumMemRecords; // Number of memory records requested by codec ++ size_t mNumCores; // Number of cores used by the codec ++ ++ UWORD32 mHeaderGenerated; ++ UWORD32 mBframes; ++ IV_ARCH_T mArch; ++ IVE_SLICE_MODE_T mSliceMode; ++ UWORD32 mSliceParam; ++ bool mHalfPelEnable; ++ UWORD32 mIInterval; ++ UWORD32 mIDRInterval; ++ UWORD32 mDisableDeblkLevel; ++ IVE_AIR_MODE_T mAIRMode; ++ UWORD32 mAIRRefreshPeriod; ++ ++ void initEncParams(); ++ OMX_ERRORTYPE initEncoder(); ++ OMX_ERRORTYPE releaseEncoder(); ++ ++ // Verifies the component role tried to be set to this OMX component is ++ // strictly video_encoder.avc ++ OMX_ERRORTYPE internalSetRoleParams( ++ const OMX_PARAM_COMPONENTROLETYPE *role); ++ ++ // Updates bitrate to reflect port settings. ++ OMX_ERRORTYPE internalSetBitrateParams( ++ const OMX_VIDEO_PARAM_BITRATETYPE *bitrate); ++ ++ OMX_ERRORTYPE internalSetConfig( ++ OMX_INDEXTYPE index, const OMX_PTR _params, bool *frameConfig); ++ ++ OMX_ERRORTYPE getConfig( ++ OMX_INDEXTYPE index, const OMX_PTR _params); ++ ++ // Handles port definition changes. ++ OMX_ERRORTYPE internalSetPortParams( ++ const OMX_PARAM_PORTDEFINITIONTYPE *port); ++ ++ OMX_ERRORTYPE internalSetFormatParams( ++ const OMX_VIDEO_PARAM_PORTFORMATTYPE *format); ++ ++ OMX_ERRORTYPE setFrameType(IV_PICTURE_CODING_TYPE_T e_frame_type); ++ OMX_ERRORTYPE setQp(); ++ OMX_ERRORTYPE setEncMode(IVE_ENC_MODE_T e_enc_mode); ++ OMX_ERRORTYPE setDimensions(); ++ OMX_ERRORTYPE setNumCores(); ++ OMX_ERRORTYPE setFrameRate(); ++ OMX_ERRORTYPE setIpeParams(); ++ OMX_ERRORTYPE setBitRate(); ++ OMX_ERRORTYPE setAirParams(); ++ OMX_ERRORTYPE setMeParams(); ++ OMX_ERRORTYPE setGopParams(); ++ OMX_ERRORTYPE setProfileParams(); ++ OMX_ERRORTYPE setDeblockParams(); ++ OMX_ERRORTYPE setVbvParams(); ++ void logVersion(); ++ OMX_ERRORTYPE setEncodeArgs( ++ ive_video_encode_ip_t *ps_encode_ip, ++ ive_video_encode_op_t *ps_encode_op, ++ OMX_BUFFERHEADERTYPE *inputBufferHeader, ++ OMX_BUFFERHEADERTYPE *outputBufferHeader); ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftAVC); ++}; ++ ++#ifdef FILE_DUMP_ENABLE ++ ++#define INPUT_DUMP_PATH "/sdcard/media/avce_input" ++#define INPUT_DUMP_EXT "yuv" ++#define OUTPUT_DUMP_PATH "/sdcard/media/avce_output" ++#define OUTPUT_DUMP_EXT "h264" ++ ++#define GENERATE_FILE_NAMES() { \ ++ GETTIME(&mTimeStart, NULL); \ ++ strcpy(mInFile, ""); \ ++ sprintf(mInFile, "%s_%ld.%ld.%s", INPUT_DUMP_PATH, \ ++ mTimeStart.tv_sec, mTimeStart.tv_usec, \ ++ INPUT_DUMP_EXT); \ ++ strcpy(mOutFile, ""); \ ++ sprintf(mOutFile, "%s_%ld.%ld.%s", OUTPUT_DUMP_PATH,\ ++ mTimeStart.tv_sec, mTimeStart.tv_usec, \ ++ OUTPUT_DUMP_EXT); \ ++} ++ ++#define CREATE_DUMP_FILE(m_filename) { \ ++ FILE *fp = fopen(m_filename, "wb"); \ ++ if (fp != NULL) { \ ++ ALOGD("Opened file %s", m_filename); \ ++ fclose(fp); \ ++ } else { \ ++ ALOGD("Could not open file %s", m_filename); \ ++ } \ ++} ++#define DUMP_TO_FILE(m_filename, m_buf, m_size) \ ++{ \ ++ FILE *fp = fopen(m_filename, "ab"); \ ++ if (fp != NULL && m_buf != NULL) { \ ++ int i; \ ++ i = fwrite(m_buf, 1, m_size, fp); \ ++ ALOGD("fwrite ret %d to write %d", i, m_size); \ ++ if (i != (int)m_size) { \ ++ ALOGD("Error in fwrite, returned %d", i); \ ++ perror("Error in write to file"); \ ++ } \ ++ fclose(fp); \ ++ } else { \ ++ ALOGD("Could not write to file %s", m_filename);\ ++ if (fp != NULL) \ ++ fclose(fp); \ ++ } \ ++} ++#else /* FILE_DUMP_ENABLE */ ++#define INPUT_DUMP_PATH ++#define INPUT_DUMP_EXT ++#define OUTPUT_DUMP_PATH ++#define OUTPUT_DUMP_EXT ++#define GENERATE_FILE_NAMES() ++#define CREATE_DUMP_FILE(m_filename) ++#define DUMP_TO_FILE(m_filename, m_buf, m_size) ++#endif /* FILE_DUMP_ENABLE */ ++ ++} // namespace android ++ ++#endif // __SOFT_AVC_ENC_H__ +diff --git a/media/libstagefright/codecs/avcenc/exports.lds b/media/libstagefright/codecs/avcenc/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/avcenc/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/flac/dec/Android.bp b/media/libstagefright/codecs/flac/dec/Android.bp +new file mode 100644 +index 0000000..d06e0b7 +--- /dev/null ++++ b/media/libstagefright/codecs/flac/dec/Android.bp +@@ -0,0 +1,41 @@ ++package { ++ default_applicable_licenses: [ ++ "frameworks_av_media_libstagefright_codecs_flac_dec_license", ++ ], ++} ++ ++// Added automatically by a large-scale-change ++// See: http://go/android-license-faq ++license { ++ name: "frameworks_av_media_libstagefright_codecs_flac_dec_license", ++ visibility: [":__subpackages__"], ++ license_kinds: [ ++ "SPDX-license-identifier-Apache-2.0", ++ ], ++ license_text: [ ++ "NOTICE", ++ ], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_flacdec", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: [ ++ "SoftFlacDecoder.cpp", ++ ], ++ ++ version_script: "exports.lds", ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ "unsigned-integer-overflow", ++ ], ++ cfi: true, ++ }, ++ ++ shared_libs: [ ++ "libstagefright_flacdec", ++ ], ++} +diff --git a/media/libstagefright/codecs/flac/dec/MODULE_LICENSE_APACHE2 b/media/libstagefright/codecs/flac/dec/MODULE_LICENSE_APACHE2 +new file mode 100644 +index 0000000..e69de29 +diff --git a/media/libstagefright/codecs/flac/dec/NOTICE b/media/libstagefright/codecs/flac/dec/NOTICE +new file mode 100644 +index 0000000..c5b1efa +--- /dev/null ++++ b/media/libstagefright/codecs/flac/dec/NOTICE +@@ -0,0 +1,190 @@ ++ ++ Copyright (c) 2005-2008, 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. ++ ++ 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. ++ ++ ++ Apache License ++ Version 2.0, January 2004 ++ http://www.apache.org/licenses/ ++ ++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION ++ ++ 1. Definitions. ++ ++ "License" shall mean the terms and conditions for use, reproduction, ++ and distribution as defined by Sections 1 through 9 of this document. ++ ++ "Licensor" shall mean the copyright owner or entity authorized by ++ the copyright owner that is granting the License. ++ ++ "Legal Entity" shall mean the union of the acting entity and all ++ other entities that control, are controlled by, or are under common ++ control with that entity. For the purposes of this definition, ++ "control" means (i) the power, direct or indirect, to cause the ++ direction or management of such entity, whether by contract or ++ otherwise, or (ii) ownership of fifty percent (50%) or more of the ++ outstanding shares, or (iii) beneficial ownership of such entity. ++ ++ "You" (or "Your") shall mean an individual or Legal Entity ++ exercising permissions granted by this License. ++ ++ "Source" form shall mean the preferred form for making modifications, ++ including but not limited to software source code, documentation ++ source, and configuration files. ++ ++ "Object" form shall mean any form resulting from mechanical ++ transformation or translation of a Source form, including but ++ not limited to compiled object code, generated documentation, ++ and conversions to other media types. ++ ++ "Work" shall mean the work of authorship, whether in Source or ++ Object form, made available under the License, as indicated by a ++ copyright notice that is included in or attached to the work ++ (an example is provided in the Appendix below). ++ ++ "Derivative Works" shall mean any work, whether in Source or Object ++ form, that is based on (or derived from) the Work and for which the ++ editorial revisions, annotations, elaborations, or other modifications ++ represent, as a whole, an original work of authorship. For the purposes ++ of this License, Derivative Works shall not include works that remain ++ separable from, or merely link (or bind by name) to the interfaces of, ++ the Work and Derivative Works thereof. ++ ++ "Contribution" shall mean any work of authorship, including ++ the original version of the Work and any modifications or additions ++ to that Work or Derivative Works thereof, that is intentionally ++ submitted to Licensor for inclusion in the Work by the copyright owner ++ or by an individual or Legal Entity authorized to submit on behalf of ++ the copyright owner. For the purposes of this definition, "submitted" ++ means any form of electronic, verbal, or written communication sent ++ to the Licensor or its representatives, including but not limited to ++ communication on electronic mailing lists, source code control systems, ++ and issue tracking systems that are managed by, or on behalf of, the ++ Licensor for the purpose of discussing and improving the Work, but ++ excluding communication that is conspicuously marked or otherwise ++ designated in writing by the copyright owner as "Not a Contribution." ++ ++ "Contributor" shall mean Licensor and any individual or Legal Entity ++ on behalf of whom a Contribution has been received by Licensor and ++ subsequently incorporated within the Work. ++ ++ 2. Grant of Copyright License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ copyright license to reproduce, prepare Derivative Works of, ++ publicly display, publicly perform, sublicense, and distribute the ++ Work and such Derivative Works in Source or Object form. ++ ++ 3. Grant of Patent License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ (except as stated in this section) patent license to make, have made, ++ use, offer to sell, sell, import, and otherwise transfer the Work, ++ where such license applies only to those patent claims licensable ++ by such Contributor that are necessarily infringed by their ++ Contribution(s) alone or by combination of their Contribution(s) ++ with the Work to which such Contribution(s) was submitted. If You ++ institute patent litigation against any entity (including a ++ cross-claim or counterclaim in a lawsuit) alleging that the Work ++ or a Contribution incorporated within the Work constitutes direct ++ or contributory patent infringement, then any patent licenses ++ granted to You under this License for that Work shall terminate ++ as of the date such litigation is filed. ++ ++ 4. Redistribution. You may reproduce and distribute copies of the ++ Work or Derivative Works thereof in any medium, with or without ++ modifications, and in Source or Object form, provided that You ++ meet the following conditions: ++ ++ (a) You must give any other recipients of the Work or ++ Derivative Works a copy of this License; and ++ ++ (b) You must cause any modified files to carry prominent notices ++ stating that You changed the files; and ++ ++ (c) You must retain, in the Source form of any Derivative Works ++ that You distribute, all copyright, patent, trademark, and ++ attribution notices from the Source form of the Work, ++ excluding those notices that do not pertain to any part of ++ the Derivative Works; and ++ ++ (d) If the Work includes a "NOTICE" text file as part of its ++ distribution, then any Derivative Works that You distribute must ++ include a readable copy of the attribution notices contained ++ within such NOTICE file, excluding those notices that do not ++ pertain to any part of the Derivative Works, in at least one ++ of the following places: within a NOTICE text file distributed ++ as part of the Derivative Works; within the Source form or ++ documentation, if provided along with the Derivative Works; or, ++ within a display generated by the Derivative Works, if and ++ wherever such third-party notices normally appear. The contents ++ of the NOTICE file are for informational purposes only and ++ do not modify the License. You may add Your own attribution ++ notices within Derivative Works that You distribute, alongside ++ or as an addendum to the NOTICE text from the Work, provided ++ that such additional attribution notices cannot be construed ++ as modifying the License. ++ ++ You may add Your own copyright statement to Your modifications and ++ may provide additional or different license terms and conditions ++ for use, reproduction, or distribution of Your modifications, or ++ for any such Derivative Works as a whole, provided Your use, ++ reproduction, and distribution of the Work otherwise complies with ++ the conditions stated in this License. ++ ++ 5. Submission of Contributions. Unless You explicitly state otherwise, ++ any Contribution intentionally submitted for inclusion in the Work ++ by You to the Licensor shall be under the terms and conditions of ++ this License, without any additional terms or conditions. ++ Notwithstanding the above, nothing herein shall supersede or modify ++ the terms of any separate license agreement you may have executed ++ with Licensor regarding such Contributions. ++ ++ 6. Trademarks. This License does not grant permission to use the trade ++ names, trademarks, service marks, or product names of the Licensor, ++ except as required for reasonable and customary use in describing the ++ origin of the Work and reproducing the content of the NOTICE file. ++ ++ 7. Disclaimer of Warranty. Unless required by applicable law or ++ agreed to in writing, Licensor provides the Work (and each ++ Contributor provides its Contributions) on an "AS IS" BASIS, ++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or ++ implied, including, without limitation, any warranties or conditions ++ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A ++ PARTICULAR PURPOSE. You are solely responsible for determining the ++ appropriateness of using or redistributing the Work and assume any ++ risks associated with Your exercise of permissions under this License. ++ ++ 8. Limitation of Liability. In no event and under no legal theory, ++ whether in tort (including negligence), contract, or otherwise, ++ unless required by applicable law (such as deliberate and grossly ++ negligent acts) or agreed to in writing, shall any Contributor be ++ liable to You for damages, including any direct, indirect, special, ++ incidental, or consequential damages of any character arising as a ++ result of this License or out of the use or inability to use the ++ Work (including but not limited to damages for loss of goodwill, ++ work stoppage, computer failure or malfunction, or any and all ++ other commercial damages or losses), even if such Contributor ++ has been advised of the possibility of such damages. ++ ++ 9. Accepting Warranty or Additional Liability. While redistributing ++ the Work or Derivative Works thereof, You may choose to offer, ++ and charge a fee for, acceptance of support, warranty, indemnity, ++ or other liability obligations and/or rights consistent with this ++ License. However, in accepting such obligations, You may act only ++ on Your own behalf and on Your sole responsibility, not on behalf ++ of any other Contributor, and only if You agree to indemnify, ++ defend, and hold each Contributor harmless for any liability ++ incurred by, or claims asserted against, such Contributor by reason ++ of your accepting any such warranty or additional liability. ++ ++ END OF TERMS AND CONDITIONS ++ +diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp +new file mode 100644 +index 0000000..d6448d3 +--- /dev/null ++++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp +@@ -0,0 +1,500 @@ ++/* ++ * 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. ++ */ ++ ++//#define LOG_NDEBUG 0 ++#define LOG_TAG "SoftFlacDecoder" ++#include ++ ++#include "SoftFlacDecoder.h" ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++namespace android { ++ ++template ++static void InitOMXParams(T *params) { ++ params->nSize = sizeof(T); ++ params->nVersion.s.nVersionMajor = 1; ++ params->nVersion.s.nVersionMinor = 0; ++ params->nVersion.s.nRevision = 0; ++ params->nVersion.s.nStep = 0; ++} ++ ++SoftFlacDecoder::SoftFlacDecoder( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SimpleSoftOMXComponent(name, callbacks, appData, component), ++ mFLACDecoder(NULL), ++ mInputBufferCount(0), ++ mHasStreamInfo(false), ++ mSignalledError(false), ++ mSawInputEOS(false), ++ mFinishedDecoder(false), ++ mOutputPortSettingsChange(NONE) { ++ ALOGV("ctor:"); ++ memset(&mStreamInfo, 0, sizeof(mStreamInfo)); ++ initPorts(); ++ initDecoder(); ++} ++ ++SoftFlacDecoder::~SoftFlacDecoder() { ++ ALOGV("dtor:"); ++ delete mFLACDecoder; ++} ++ ++void SoftFlacDecoder::initPorts() { ++ ALOGV("initPorts:"); ++ OMX_PARAM_PORTDEFINITIONTYPE def; ++ InitOMXParams(&def); ++ ++ def.nPortIndex = 0; ++ def.eDir = OMX_DirInput; ++ def.nBufferCountMin = kNumInputBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = 32768; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 1; ++ ++ def.format.audio.cMIMEType = const_cast("audio/flac"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingFLAC; ++ ++ addPort(def); ++ ++ def.nPortIndex = 1; ++ def.eDir = OMX_DirOutput; ++ def.nBufferCountMin = kNumOutputBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = kNumSamplesPerFrame * FLACDecoder::kMaxChannels * sizeof(float); ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = sizeof(float); ++ ++ def.format.audio.cMIMEType = const_cast("audio/raw"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; ++ ++ addPort(def); ++} ++ ++void SoftFlacDecoder::initDecoder() { ++ ALOGV("initDecoder:"); ++ mFLACDecoder = FLACDecoder::Create(); ++ if (mFLACDecoder == NULL) { ++ ALOGE("initDecoder: failed to create FLACDecoder"); ++ mSignalledError = true; ++ } ++} ++ ++OMX_ERRORTYPE SoftFlacDecoder::initCheck() const { ++ if (mSignalledError) { ++ if (mFLACDecoder == NULL) { ++ ALOGE("initCheck: failed due to NULL encoder"); ++ return OMX_ErrorDynamicResourcesUnavailable; ++ } ++ return OMX_ErrorUndefined; ++ } ++ ++ return SimpleSoftOMXComponent::initCheck(); ++} ++ ++OMX_ERRORTYPE SoftFlacDecoder::internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params) { ++ ALOGV("internalGetParameter: index(%x)", index); ++ switch ((OMX_U32)index) { ++ case OMX_IndexParamAudioPortFormat: ++ { ++ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (formatParams->nIndex > 0) { ++ return OMX_ErrorNoMore; ++ } ++ ++ formatParams->eEncoding = ++ (formatParams->nPortIndex == 0) ++ ? OMX_AUDIO_CodingFLAC : OMX_AUDIO_CodingPCM; ++ ++ return OMX_ErrorNone; ++ } ++ case OMX_IndexParamAudioFlac: ++ { ++ OMX_AUDIO_PARAM_FLACTYPE *flacParams = ++ (OMX_AUDIO_PARAM_FLACTYPE *)params; ++ ++ if (!isValidOMXParam(flacParams)) { ++ ALOGE("internalGetParameter(OMX_IndexParamAudioFlac): invalid omx params"); ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (flacParams->nPortIndex != 0) { ++ ALOGE("internalGetParameter(OMX_IndexParamAudioFlac): bad port index"); ++ return OMX_ErrorBadPortIndex; ++ } ++ ++ flacParams->nCompressionLevel = 0; ++ ++ if (isConfigured()) { ++ flacParams->nChannels = mStreamInfo.channels; ++ flacParams->nSampleRate = mStreamInfo.sample_rate; ++ } else { ++ flacParams->nChannels = 2; ++ flacParams->nSampleRate = 44100; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ ALOGE("internalGetParameter(OMX_IndexParamAudioPcm): invalid omx params"); ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 1) { ++ ALOGE("internalGetParameter(OMX_IndexParamAudioPcm): bad port index"); ++ return OMX_ErrorBadPortIndex; ++ } ++ ++ pcmParams->eNumData = mNumericalData; ++ pcmParams->eEndian = OMX_EndianBig; ++ pcmParams->bInterleaved = OMX_TRUE; ++ pcmParams->nBitPerSample = mBitsPerSample; ++ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; ++ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; ++ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; ++ pcmParams->eChannelMapping[2] = OMX_AUDIO_ChannelCF; ++ pcmParams->eChannelMapping[3] = OMX_AUDIO_ChannelLFE; ++ pcmParams->eChannelMapping[4] = OMX_AUDIO_ChannelLS; ++ pcmParams->eChannelMapping[5] = OMX_AUDIO_ChannelRS; ++ ++ if (isConfigured()) { ++ pcmParams->nChannels = mStreamInfo.channels; ++ pcmParams->nSamplingRate = mStreamInfo.sample_rate; ++ } else { ++ pcmParams->nChannels = 2; ++ pcmParams->nSamplingRate = 44100; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalGetParameter(index, params); ++ } ++} ++ ++OMX_ERRORTYPE SoftFlacDecoder::internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params) { ++ ALOGV("internalSetParameter: index(%x)", (int)index); ++ switch ((int)index) { ++ case OMX_IndexParamStandardComponentRole: ++ { ++ const OMX_PARAM_COMPONENTROLETYPE *roleParams = ++ (const OMX_PARAM_COMPONENTROLETYPE *)params; ++ ++ if (!isValidOMXParam(roleParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (strncmp((const char *)roleParams->cRole, ++ "audio_decoder.flac", ++ OMX_MAX_STRINGNAME_SIZE - 1) != 0) { ++ return OMX_ErrorInvalidComponentName; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPortFormat: ++ { ++ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if ((formatParams->nPortIndex == 0 ++ && formatParams->eEncoding != OMX_AUDIO_CodingFLAC) ++ || (formatParams->nPortIndex == 1 ++ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 1) { ++ return OMX_ErrorBadPortIndex; ++ } ++ ++ if (pcmParams->eNumData == OMX_NumericalDataFloat && pcmParams->nBitPerSample == 32) { ++ mNumericalData = OMX_NumericalDataFloat; ++ mBitsPerSample = 32; ++ } else if (pcmParams->eNumData == OMX_NumericalDataSigned ++ && pcmParams->nBitPerSample == 16) { ++ mNumericalData = OMX_NumericalDataSigned; ++ mBitsPerSample = 16; ++ } else { ++ ALOGE("Invalid eNumData %d, nBitsPerSample %d", ++ pcmParams->eNumData, pcmParams->nBitPerSample); ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalSetParameter(index, params); ++ } ++} ++ ++bool SoftFlacDecoder::isConfigured() const { ++ return mHasStreamInfo; ++} ++ ++void SoftFlacDecoder::onQueueFilled(OMX_U32 /* portIndex */) { ++ if (mSignalledError || mOutputPortSettingsChange != NONE) { ++ return; ++ } ++ ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ ++ const bool outputFloat = mNumericalData == OMX_NumericalDataFloat; ++ ++ ALOGV("onQueueFilled %d/%d:", inQueue.empty(), outQueue.empty()); ++ while ((!inQueue.empty() || mSawInputEOS) && !outQueue.empty() && !mFinishedDecoder) { ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ void *outBuffer = reinterpret_cast(outHeader->pBuffer + outHeader->nOffset); ++ size_t outBufferSize = outHeader->nAllocLen - outHeader->nOffset; ++ int64_t timeStamp = 0; ++ ++ if (!inQueue.empty()) { ++ BufferInfo *inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++ uint8_t* inBuffer = inHeader->pBuffer + inHeader->nOffset; ++ uint32_t inBufferLength = inHeader->nFilledLen; ++ ALOGV("input: %u bytes", inBufferLength); ++ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ ALOGV("saw EOS"); ++ mSawInputEOS = true; ++ if (mInputBufferCount == 0 && inHeader->nFilledLen == 0) { ++ // first buffer was empty and EOS: signal EOS on output and return ++ ALOGV("empty first EOS"); ++ outHeader->nFilledLen = 0; ++ outHeader->nTimeStamp = inHeader->nTimeStamp; ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ notifyFillBufferDone(outHeader); ++ mFinishedDecoder = true; ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ notifyEmptyBufferDone(inHeader); ++ return; ++ } ++ } ++ ++ if (mInputBufferCount == 0 && !(inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) { ++ ALOGE("onQueueFilled: first buffer should have OMX_BUFFERFLAG_CODECCONFIG set"); ++ inHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG; ++ } ++ if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) != 0) { ++ ALOGV("received config buffer of size %u", inBufferLength); ++ status_t decoderErr = mFLACDecoder->parseMetadata(inBuffer, inBufferLength); ++ mInputBufferCount++; ++ ++ if (decoderErr != OK && decoderErr != WOULD_BLOCK) { ++ ALOGE("onQueueFilled: FLACDecoder parseMetaData returns error %d", decoderErr); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorStreamCorrupt, decoderErr, NULL); ++ return; ++ } ++ ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ notifyEmptyBufferDone(inHeader); ++ ++ if (decoderErr == WOULD_BLOCK) { ++ continue; ++ } ++ mStreamInfo = mFLACDecoder->getStreamInfo(); ++ mHasStreamInfo = true; ++ ++ // Only send out port settings changed event if both sample rate ++ // and numChannels are valid. ++ if (mStreamInfo.sample_rate && mStreamInfo.channels) { ++ ALOGD("onQueueFilled: initially configuring decoder: %d Hz, %d channels", ++ mStreamInfo.sample_rate, mStreamInfo.channels); ++ ++ notify(OMX_EventPortSettingsChanged, 1, 0, NULL); ++ mOutputPortSettingsChange = AWAITING_DISABLED; ++ } ++ return; ++ } ++ ++ status_t decoderErr = mFLACDecoder->decodeOneFrame( ++ inBuffer, inBufferLength, outBuffer, &outBufferSize, outputFloat); ++ if (decoderErr != OK) { ++ ALOGE("onQueueFilled: FLACDecoder decodeOneFrame returns error %d", decoderErr); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorStreamCorrupt, decoderErr, NULL); ++ return; ++ } ++ ++ mInputBufferCount++; ++ timeStamp = inHeader->nTimeStamp; ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ notifyEmptyBufferDone(inHeader); ++ ++ if (outBufferSize == 0) { ++ ALOGV("no output, trying again"); ++ continue; ++ } ++ } else if (mSawInputEOS) { ++ status_t decoderErr = mFLACDecoder->decodeOneFrame( ++ nullptr /* inBuffer */, 0 /* inBufferLen */, ++ outBuffer, &outBufferSize, outputFloat); ++ mFinishedDecoder = true; ++ if (decoderErr != OK) { ++ ALOGE("onQueueFilled: FLACDecoder finish returns error %d", decoderErr); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorStreamCorrupt, decoderErr, NULL); ++ return; ++ } ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ } else { ++ // no more input buffers at this time, loop and see if there is more output ++ continue; ++ } ++ ++ outHeader->nFilledLen = outBufferSize; ++ outHeader->nTimeStamp = timeStamp; ++ ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ notifyFillBufferDone(outHeader); ++ } ++} ++ ++void SoftFlacDecoder::onPortFlushCompleted(OMX_U32 portIndex) { ++ ALOGV("onPortFlushCompleted: portIndex(%u)", portIndex); ++ if (portIndex == 0) { ++ drainDecoder(); ++ } ++} ++ ++void SoftFlacDecoder::drainDecoder() { ++ mFLACDecoder->flush(); ++ mSawInputEOS = false; ++ mFinishedDecoder = false; ++} ++ ++void SoftFlacDecoder::onReset() { ++ ALOGV("onReset"); ++ drainDecoder(); ++ ++ memset(&mStreamInfo, 0, sizeof(mStreamInfo)); ++ mHasStreamInfo = false; ++ mInputBufferCount = 0; ++ mSignalledError = false; ++ mOutputPortSettingsChange = NONE; ++} ++ ++void SoftFlacDecoder::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { ++ ALOGV("onPortEnableCompleted: portIndex(%u), enabled(%d)", portIndex, enabled); ++ if (portIndex != 1) { ++ return; ++ } ++ ++ switch (mOutputPortSettingsChange) { ++ case NONE: ++ break; ++ ++ case AWAITING_DISABLED: ++ { ++ CHECK(!enabled); ++ mOutputPortSettingsChange = AWAITING_ENABLED; ++ PortInfo *info = editPortInfo(1 /* portIndex */); ++ if (!info->mDef.bEnabled) { ++ info->mDef.nBufferSize = ++ mStreamInfo.max_blocksize * mStreamInfo.channels * sizeof(float); ++ } ++ break; ++ } ++ ++ default: ++ { ++ CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); ++ CHECK(enabled); ++ mOutputPortSettingsChange = NONE; ++ break; ++ } ++ } ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ ALOGV("createSoftOMXComponent: flac decoder"); ++ return new android::SoftFlacDecoder(name, callbacks, appData, component); ++} +diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h +new file mode 100644 +index 0000000..ba02074 +--- /dev/null ++++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h +@@ -0,0 +1,81 @@ ++/* ++ * 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 SOFT_FLAC_DECODER_H ++#define SOFT_FLAC_DECODER_H ++ ++#include "FLACDecoder.h" ++#include ++ ++namespace android { ++ ++struct SoftFlacDecoder : public SimpleSoftOMXComponent { ++ SoftFlacDecoder(const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++ virtual OMX_ERRORTYPE initCheck() const override; ++ ++protected: ++ virtual ~SoftFlacDecoder(); ++ ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params) override; ++ ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params) override; ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ virtual void onPortFlushCompleted(OMX_U32 portIndex) override; ++ virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled) override; ++ virtual void onReset() override; ++ ++private: ++ static constexpr unsigned int kNumSamplesPerFrame = 2048; // adjusted based on stream. ++ ++ enum { ++ kNumInputBuffers = 4, ++ kNumOutputBuffers = 4, ++ }; ++ OMX_NUMERICALDATATYPE mNumericalData = OMX_NumericalDataSigned; ++ OMX_U32 mBitsPerSample = 16; ++ ++ FLACDecoder *mFLACDecoder; ++ FLAC__StreamMetadata_StreamInfo mStreamInfo; ++ size_t mInputBufferCount; ++ bool mHasStreamInfo; ++ bool mSignalledError; ++ bool mSawInputEOS; ++ bool mFinishedDecoder; ++ ++ enum { ++ NONE, ++ AWAITING_DISABLED, ++ AWAITING_ENABLED ++ } mOutputPortSettingsChange; ++ ++ void initPorts(); ++ void initDecoder(); ++ bool isConfigured() const; ++ void drainDecoder(); ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftFlacDecoder); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_FLAC_DECODER_H +diff --git a/media/libstagefright/codecs/flac/dec/exports.lds b/media/libstagefright/codecs/flac/dec/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/flac/dec/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/flac/enc/Android.bp b/media/libstagefright/codecs/flac/enc/Android.bp +new file mode 100644 +index 0000000..59a4675 +--- /dev/null ++++ b/media/libstagefright/codecs/flac/enc/Android.bp +@@ -0,0 +1,43 @@ ++package { ++ default_applicable_licenses: [ ++ "frameworks_av_media_libstagefright_codecs_flac_enc_license", ++ ], ++} ++ ++// Added automatically by a large-scale-change ++// See: http://go/android-license-faq ++license { ++ name: "frameworks_av_media_libstagefright_codecs_flac_enc_license", ++ visibility: [":__subpackages__"], ++ license_kinds: [ ++ "SPDX-license-identifier-Apache-2.0", ++ ], ++ license_text: [ ++ "NOTICE", ++ ], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_flacenc", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: ["SoftFlacEncoder.cpp"], ++ ++ version_script: "exports.lds", ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ "unsigned-integer-overflow", ++ ], ++ cfi: true, ++ }, ++ ++ header_libs: ["libbase_headers"], ++ shared_libs: [ ++ "libaudioutils", ++ ], ++ static_libs: [ ++ "libFLAC", ++ ], ++} +diff --git a/media/libstagefright/codecs/flac/enc/MODULE_LICENSE_APACHE2 b/media/libstagefright/codecs/flac/enc/MODULE_LICENSE_APACHE2 +new file mode 100644 +index 0000000..e69de29 +diff --git a/media/libstagefright/codecs/flac/enc/NOTICE b/media/libstagefright/codecs/flac/enc/NOTICE +new file mode 100644 +index 0000000..c5b1efa +--- /dev/null ++++ b/media/libstagefright/codecs/flac/enc/NOTICE +@@ -0,0 +1,190 @@ ++ ++ Copyright (c) 2005-2008, 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. ++ ++ 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. ++ ++ ++ Apache License ++ Version 2.0, January 2004 ++ http://www.apache.org/licenses/ ++ ++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION ++ ++ 1. Definitions. ++ ++ "License" shall mean the terms and conditions for use, reproduction, ++ and distribution as defined by Sections 1 through 9 of this document. ++ ++ "Licensor" shall mean the copyright owner or entity authorized by ++ the copyright owner that is granting the License. ++ ++ "Legal Entity" shall mean the union of the acting entity and all ++ other entities that control, are controlled by, or are under common ++ control with that entity. For the purposes of this definition, ++ "control" means (i) the power, direct or indirect, to cause the ++ direction or management of such entity, whether by contract or ++ otherwise, or (ii) ownership of fifty percent (50%) or more of the ++ outstanding shares, or (iii) beneficial ownership of such entity. ++ ++ "You" (or "Your") shall mean an individual or Legal Entity ++ exercising permissions granted by this License. ++ ++ "Source" form shall mean the preferred form for making modifications, ++ including but not limited to software source code, documentation ++ source, and configuration files. ++ ++ "Object" form shall mean any form resulting from mechanical ++ transformation or translation of a Source form, including but ++ not limited to compiled object code, generated documentation, ++ and conversions to other media types. ++ ++ "Work" shall mean the work of authorship, whether in Source or ++ Object form, made available under the License, as indicated by a ++ copyright notice that is included in or attached to the work ++ (an example is provided in the Appendix below). ++ ++ "Derivative Works" shall mean any work, whether in Source or Object ++ form, that is based on (or derived from) the Work and for which the ++ editorial revisions, annotations, elaborations, or other modifications ++ represent, as a whole, an original work of authorship. For the purposes ++ of this License, Derivative Works shall not include works that remain ++ separable from, or merely link (or bind by name) to the interfaces of, ++ the Work and Derivative Works thereof. ++ ++ "Contribution" shall mean any work of authorship, including ++ the original version of the Work and any modifications or additions ++ to that Work or Derivative Works thereof, that is intentionally ++ submitted to Licensor for inclusion in the Work by the copyright owner ++ or by an individual or Legal Entity authorized to submit on behalf of ++ the copyright owner. For the purposes of this definition, "submitted" ++ means any form of electronic, verbal, or written communication sent ++ to the Licensor or its representatives, including but not limited to ++ communication on electronic mailing lists, source code control systems, ++ and issue tracking systems that are managed by, or on behalf of, the ++ Licensor for the purpose of discussing and improving the Work, but ++ excluding communication that is conspicuously marked or otherwise ++ designated in writing by the copyright owner as "Not a Contribution." ++ ++ "Contributor" shall mean Licensor and any individual or Legal Entity ++ on behalf of whom a Contribution has been received by Licensor and ++ subsequently incorporated within the Work. ++ ++ 2. Grant of Copyright License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ copyright license to reproduce, prepare Derivative Works of, ++ publicly display, publicly perform, sublicense, and distribute the ++ Work and such Derivative Works in Source or Object form. ++ ++ 3. Grant of Patent License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ (except as stated in this section) patent license to make, have made, ++ use, offer to sell, sell, import, and otherwise transfer the Work, ++ where such license applies only to those patent claims licensable ++ by such Contributor that are necessarily infringed by their ++ Contribution(s) alone or by combination of their Contribution(s) ++ with the Work to which such Contribution(s) was submitted. If You ++ institute patent litigation against any entity (including a ++ cross-claim or counterclaim in a lawsuit) alleging that the Work ++ or a Contribution incorporated within the Work constitutes direct ++ or contributory patent infringement, then any patent licenses ++ granted to You under this License for that Work shall terminate ++ as of the date such litigation is filed. ++ ++ 4. Redistribution. You may reproduce and distribute copies of the ++ Work or Derivative Works thereof in any medium, with or without ++ modifications, and in Source or Object form, provided that You ++ meet the following conditions: ++ ++ (a) You must give any other recipients of the Work or ++ Derivative Works a copy of this License; and ++ ++ (b) You must cause any modified files to carry prominent notices ++ stating that You changed the files; and ++ ++ (c) You must retain, in the Source form of any Derivative Works ++ that You distribute, all copyright, patent, trademark, and ++ attribution notices from the Source form of the Work, ++ excluding those notices that do not pertain to any part of ++ the Derivative Works; and ++ ++ (d) If the Work includes a "NOTICE" text file as part of its ++ distribution, then any Derivative Works that You distribute must ++ include a readable copy of the attribution notices contained ++ within such NOTICE file, excluding those notices that do not ++ pertain to any part of the Derivative Works, in at least one ++ of the following places: within a NOTICE text file distributed ++ as part of the Derivative Works; within the Source form or ++ documentation, if provided along with the Derivative Works; or, ++ within a display generated by the Derivative Works, if and ++ wherever such third-party notices normally appear. The contents ++ of the NOTICE file are for informational purposes only and ++ do not modify the License. You may add Your own attribution ++ notices within Derivative Works that You distribute, alongside ++ or as an addendum to the NOTICE text from the Work, provided ++ that such additional attribution notices cannot be construed ++ as modifying the License. ++ ++ You may add Your own copyright statement to Your modifications and ++ may provide additional or different license terms and conditions ++ for use, reproduction, or distribution of Your modifications, or ++ for any such Derivative Works as a whole, provided Your use, ++ reproduction, and distribution of the Work otherwise complies with ++ the conditions stated in this License. ++ ++ 5. Submission of Contributions. Unless You explicitly state otherwise, ++ any Contribution intentionally submitted for inclusion in the Work ++ by You to the Licensor shall be under the terms and conditions of ++ this License, without any additional terms or conditions. ++ Notwithstanding the above, nothing herein shall supersede or modify ++ the terms of any separate license agreement you may have executed ++ with Licensor regarding such Contributions. ++ ++ 6. Trademarks. This License does not grant permission to use the trade ++ names, trademarks, service marks, or product names of the Licensor, ++ except as required for reasonable and customary use in describing the ++ origin of the Work and reproducing the content of the NOTICE file. ++ ++ 7. Disclaimer of Warranty. Unless required by applicable law or ++ agreed to in writing, Licensor provides the Work (and each ++ Contributor provides its Contributions) on an "AS IS" BASIS, ++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or ++ implied, including, without limitation, any warranties or conditions ++ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A ++ PARTICULAR PURPOSE. You are solely responsible for determining the ++ appropriateness of using or redistributing the Work and assume any ++ risks associated with Your exercise of permissions under this License. ++ ++ 8. Limitation of Liability. In no event and under no legal theory, ++ whether in tort (including negligence), contract, or otherwise, ++ unless required by applicable law (such as deliberate and grossly ++ negligent acts) or agreed to in writing, shall any Contributor be ++ liable to You for damages, including any direct, indirect, special, ++ incidental, or consequential damages of any character arising as a ++ result of this License or out of the use or inability to use the ++ Work (including but not limited to damages for loss of goodwill, ++ work stoppage, computer failure or malfunction, or any and all ++ other commercial damages or losses), even if such Contributor ++ has been advised of the possibility of such damages. ++ ++ 9. Accepting Warranty or Additional Liability. While redistributing ++ the Work or Derivative Works thereof, You may choose to offer, ++ and charge a fee for, acceptance of support, warranty, indemnity, ++ or other liability obligations and/or rights consistent with this ++ License. However, in accepting such obligations, You may act only ++ on Your own behalf and on Your sole responsibility, not on behalf ++ of any other Contributor, and only if You agree to indemnify, ++ defend, and hold each Contributor harmless for any liability ++ incurred by, or claims asserted against, such Contributor by reason ++ of your accepting any such warranty or additional liability. ++ ++ END OF TERMS AND CONDITIONS ++ +diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp +new file mode 100644 +index 0000000..24216a2 +--- /dev/null ++++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp +@@ -0,0 +1,601 @@ ++/* ++ * Copyright (C) 2012 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 "SoftFlacEncoder" ++#include ++#include ++ ++#include "SoftFlacEncoder.h" ++#include ++#include ++#include ++ ++#define FLAC_COMPRESSION_LEVEL_MIN 0 ++#define FLAC_COMPRESSION_LEVEL_DEFAULT 5 ++#define FLAC_COMPRESSION_LEVEL_MAX 8 ++ ++#if LOG_NDEBUG ++#define UNUSED_UNLESS_VERBOSE(x) (void)(x) ++#else ++#define UNUSED_UNLESS_VERBOSE(x) ++#endif ++ ++namespace android { ++ ++template ++static void InitOMXParams(T *params) { ++ params->nSize = sizeof(T); ++ params->nVersion.s.nVersionMajor = 1; ++ params->nVersion.s.nVersionMinor = 0; ++ params->nVersion.s.nRevision = 0; ++ params->nVersion.s.nStep = 0; ++} ++ ++SoftFlacEncoder::SoftFlacEncoder( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SimpleSoftOMXComponent(name, callbacks, appData, component), ++ mSignalledError(false), ++ mNumChannels(1), ++ mSampleRate(44100), ++ mCompressionLevel(FLAC_COMPRESSION_LEVEL_DEFAULT), ++ mEncoderWriteData(false), ++ mEncoderReturnedEncodedData(false), ++ mSawInputEOS(false), ++ mSentOutputEOS(false), ++ mEncoderReturnedNbBytes(0), ++ mInputBufferPcm32(NULL), ++ mHeaderOffset(0), ++ mHeaderComplete(false), ++ mWroteHeader(false) ++{ ++ ALOGV("SoftFlacEncoder::SoftFlacEncoder(name=%s)", name); ++ initPorts(); ++ ++ mFlacStreamEncoder = FLAC__stream_encoder_new(); ++ if (mFlacStreamEncoder == NULL) { ++ ALOGE("SoftFlacEncoder::SoftFlacEncoder(name=%s) error instantiating FLAC encoder", name); ++ mSignalledError = true; ++ } ++ ++ if (!mSignalledError) { // no use allocating input buffer if we had an error above ++ // 2x the pcm16 samples can exist with the same size as pcmFloat samples. ++ mInputBufferPcm32 = (FLAC__int32*) malloc( ++ sizeof(FLAC__int32) * kNumSamplesPerFrame * kMaxChannels * 2); ++ if (mInputBufferPcm32 == NULL) { ++ ALOGE("SoftFlacEncoder::SoftFlacEncoder(name=%s) error allocating internal input buffer", name); ++ mSignalledError = true; ++ } ++ } ++} ++ ++SoftFlacEncoder::~SoftFlacEncoder() { ++ ALOGV("SoftFlacEncoder::~SoftFlacEncoder()"); ++ if (mFlacStreamEncoder != NULL) { ++ FLAC__stream_encoder_delete(mFlacStreamEncoder); ++ mFlacStreamEncoder = NULL; ++ } ++ free(mInputBufferPcm32); ++ mInputBufferPcm32 = NULL; ++} ++ ++OMX_ERRORTYPE SoftFlacEncoder::initCheck() const { ++ if (mSignalledError) { ++ if (mFlacStreamEncoder == NULL) { ++ ALOGE("initCheck() failed due to NULL encoder"); ++ } else if (mInputBufferPcm32 == NULL) { ++ ALOGE("initCheck() failed due to error allocating internal input buffer"); ++ } ++ return OMX_ErrorUndefined; ++ } else { ++ return SimpleSoftOMXComponent::initCheck(); ++ } ++} ++ ++void SoftFlacEncoder::initPorts() { ++ ALOGV("SoftFlacEncoder::initPorts()"); ++ ++ OMX_PARAM_PORTDEFINITIONTYPE def; ++ InitOMXParams(&def); ++ ++ // configure input port of the encoder ++ def.nPortIndex = 0; ++ def.eDir = OMX_DirInput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = kMaxInputBufferSize; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = sizeof(float); ++ ++ def.format.audio.cMIMEType = const_cast("audio/raw"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; ++ ++ addPort(def); ++ ++ // configure output port of the encoder ++ def.nPortIndex = 1; ++ def.eDir = OMX_DirOutput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = kMaxOutputBufferSize; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 1; ++ ++ def.format.audio.cMIMEType = const_cast(MEDIA_MIMETYPE_AUDIO_FLAC); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingFLAC; ++ ++ addPort(def); ++} ++ ++OMX_ERRORTYPE SoftFlacEncoder::internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params) { ++ ALOGV("SoftFlacEncoder::internalGetParameter(index=0x%x)", index); ++ ++ switch (index) { ++ case OMX_IndexParamAudioPortFormat: ++ { ++ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (formatParams->nIndex > 0) { ++ return OMX_ErrorNoMore; ++ } ++ ++ formatParams->eEncoding = ++ (formatParams->nPortIndex == 0) ++ ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingFLAC; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ pcmParams->eNumData = mNumericalData; ++ pcmParams->eEndian = OMX_EndianBig; ++ pcmParams->bInterleaved = OMX_TRUE; ++ pcmParams->nBitPerSample = mBitsPerSample; ++ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; ++ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; ++ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; ++ ++ pcmParams->nChannels = mNumChannels; ++ pcmParams->nSamplingRate = mSampleRate; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioFlac: ++ { ++ OMX_AUDIO_PARAM_FLACTYPE *flacParams = (OMX_AUDIO_PARAM_FLACTYPE *)params; ++ ++ if (!isValidOMXParam(flacParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (flacParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ flacParams->nCompressionLevel = mCompressionLevel; ++ flacParams->nChannels = mNumChannels; ++ flacParams->nSampleRate = mSampleRate; ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalGetParameter(index, params); ++ } ++} ++ ++OMX_ERRORTYPE SoftFlacEncoder::internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamAudioPortFormat: ++ { ++ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if ((formatParams->nPortIndex == 0 ++ && formatParams->eEncoding != OMX_AUDIO_CodingPCM) ++ || (formatParams->nPortIndex == 1 ++ && formatParams->eEncoding != OMX_AUDIO_CodingFLAC)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ ALOGV("SoftFlacEncoder::internalSetParameter(OMX_IndexParamAudioPcm)"); ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 0) { ++ ALOGE("SoftFlacEncoder::internalSetParameter() Error #1"); ++ return OMX_ErrorUndefined; ++ } ++ ++ if (pcmParams->nChannels < 1 || pcmParams->nChannels > kMaxChannels) { ++ return OMX_ErrorUndefined; ++ } ++ ++ mNumChannels = pcmParams->nChannels; ++ mSampleRate = pcmParams->nSamplingRate; ++ ++ if (pcmParams->eNumData == OMX_NumericalDataFloat && pcmParams->nBitPerSample == 32) { ++ mNumericalData = OMX_NumericalDataFloat; ++ mBitsPerSample = 32; ++ } else if (pcmParams->eNumData == OMX_NumericalDataSigned ++ && pcmParams->nBitPerSample == 16) { ++ mNumericalData = OMX_NumericalDataSigned; ++ mBitsPerSample = 16; ++ } else { ++ ALOGE("%s: invalid eNumData %d, nBitsPerSample %d", ++ __func__, pcmParams->eNumData, pcmParams->nBitPerSample); ++ return OMX_ErrorUndefined; ++ } ++ ++ ALOGV("will encode %d channels at %dHz", mNumChannels, mSampleRate); ++ ++ return configureEncoder(); ++ } ++ ++ case OMX_IndexParamStandardComponentRole: ++ { ++ ALOGV("SoftFlacEncoder::internalSetParameter(OMX_IndexParamStandardComponentRole)"); ++ const OMX_PARAM_COMPONENTROLETYPE *roleParams = ++ (const OMX_PARAM_COMPONENTROLETYPE *)params; ++ ++ if (!isValidOMXParam(roleParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (strncmp((const char *)roleParams->cRole, ++ "audio_encoder.flac", ++ OMX_MAX_STRINGNAME_SIZE - 1)) { ++ ALOGE("SoftFlacEncoder::internalSetParameter(OMX_IndexParamStandardComponentRole)" ++ "error"); ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioFlac: ++ { ++ // used only for setting the compression level ++ OMX_AUDIO_PARAM_FLACTYPE *flacParams = (OMX_AUDIO_PARAM_FLACTYPE *)params; ++ ++ if (!isValidOMXParam(flacParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (flacParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ mCompressionLevel = flacParams->nCompressionLevel; // range clamping done inside encoder ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamPortDefinition: ++ { ++ OMX_PARAM_PORTDEFINITIONTYPE *defParams = ++ (OMX_PARAM_PORTDEFINITIONTYPE *)params; ++ ++ if (!isValidOMXParam(defParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (defParams->nPortIndex == 0) { ++ if (defParams->nBufferSize > kMaxInputBufferSize) { ++ ALOGE("Input buffer size must be at most %d bytes", ++ kMaxInputBufferSize); ++ return OMX_ErrorUnsupportedSetting; ++ } ++ } ++ ++ FALLTHROUGH_INTENDED; ++ } ++ ++ default: ++ ALOGV("SoftFlacEncoder::internalSetParameter(default)"); ++ return SimpleSoftOMXComponent::internalSetParameter(index, params); ++ } ++} ++ ++void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) { ++ UNUSED_UNLESS_VERBOSE(portIndex); ++ ALOGV("SoftFlacEncoder::onQueueFilled(portIndex=%d)", portIndex); ++ ++ if (mSignalledError) { ++ return; ++ } ++ ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ ++ const bool inputFloat = mNumericalData == OMX_NumericalDataFloat; ++ const size_t sampleSize = inputFloat ? sizeof(float) : sizeof(int16_t); ++ const size_t frameSize = sampleSize * mNumChannels; ++ ++ FLAC__bool ok = true; ++ ++ while ((!inQueue.empty() || mSawInputEOS) && !outQueue.empty() && !mSentOutputEOS) { ++ if (!inQueue.empty()) { ++ BufferInfo *inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++ ++ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ ALOGV("saw EOS on buffer of size %u", inHeader->nFilledLen); ++ mSawInputEOS = true; ++ } ++ ++ if (inHeader->nFilledLen > kMaxInputBufferSize) { ++ ALOGE("input buffer too large (%d).", inHeader->nFilledLen); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ ++ assert(mNumChannels != 0); ++ mEncoderWriteData = true; ++ mEncoderReturnedEncodedData = false; ++ mEncoderReturnedNbBytes = 0; ++ if (inHeader->nFilledLen) { ++ mCurrentInputTimeStamp = inHeader->nTimeStamp; ++ ++ const unsigned nbInputFrames = inHeader->nFilledLen / frameSize; ++ const unsigned nbInputSamples = inHeader->nFilledLen / sampleSize; ++ ++ if (inputFloat) { ++ CHECK_LE(nbInputSamples, kNumSamplesPerFrame * kMaxChannels); ++ const float * const pcmFloat = reinterpret_cast(inHeader->pBuffer); ++ memcpy_to_q8_23_from_float_with_clamp( ++ mInputBufferPcm32, pcmFloat, nbInputSamples); ++ } else { ++ // note nbInputSamples may be 2x as large for pcm16 data. ++ CHECK_LE(nbInputSamples, kNumSamplesPerFrame * kMaxChannels * 2); ++ const int16_t * const pcm16 = reinterpret_cast(inHeader->pBuffer); ++ for (unsigned i = 0; i < nbInputSamples; ++i) { ++ mInputBufferPcm32[i] = (FLAC__int32) pcm16[i]; ++ } ++ } ++ ALOGV(" about to encode %u samples per channel", nbInputFrames); ++ ok = FLAC__stream_encoder_process_interleaved( ++ mFlacStreamEncoder, ++ mInputBufferPcm32, ++ nbInputFrames /*samples per channel*/ ); ++ } ++ ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ } ++ ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ ++ if (ok) { ++ ALOGV("encoded %d, bytes %lld, eos %d", mEncoderReturnedEncodedData, ++ (long long )mEncoderReturnedNbBytes, mSawInputEOS); ++ if (mSawInputEOS && !mEncoderReturnedEncodedData) { ++ ALOGV("finishing encoder"); ++ mSentOutputEOS = true; ++ FLAC__stream_encoder_finish(mFlacStreamEncoder); ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ } ++ if (mSawInputEOS || mEncoderReturnedEncodedData) { ++ ALOGV(" dequeueing buffer on output port after writing data"); ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ outInfo = NULL; ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ mEncoderReturnedEncodedData = false; ++ } ++ } else { ++ ALOGE(" error encountered during encoding"); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ ++ } ++} ++ ++FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable( ++ const FLAC__byte buffer[], ++ size_t bytes, unsigned samples, ++ unsigned current_frame) { ++ UNUSED_UNLESS_VERBOSE(current_frame); ++ ALOGV("SoftFlacEncoder::onEncodedFlacAvailable(bytes=%zu, samples=%u, curr_frame=%u)", ++ bytes, samples, current_frame); ++ ++ if (samples == 0) { ++ ALOGV("saving %zu bytes of header", bytes); ++ if (mHeaderOffset + bytes > sizeof(mHeader) || mHeaderComplete) { ++ ALOGW("header is too big, or header already received"); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ } else { ++ memcpy(mHeader + mHeaderOffset, buffer, bytes); ++ mHeaderOffset += bytes;// will contain header size when finished receiving header ++ if (buffer[0] & 0x80) { ++ mHeaderComplete = true; ++ } ++ } ++ return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; ++ } ++ ++ if ((samples == 0) || !mEncoderWriteData) { ++ // called by the encoder because there's header data to save, but it's not the role ++ // of this component (unless WRITE_FLAC_HEADER_IN_FIRST_BUFFER is defined) ++ ALOGV("ignoring %zu bytes of header data (samples=%d)", bytes, samples); ++ return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; ++ } ++ ++ List &outQueue = getPortQueue(1); ++ CHECK(!outQueue.empty()); ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ ++ if (mHeaderComplete && !mWroteHeader) { ++ ALOGV(" writing %d bytes of header on output port", mHeaderOffset); ++ memcpy(outHeader->pBuffer + outHeader->nOffset + outHeader->nFilledLen, ++ mHeader, mHeaderOffset); ++ outHeader->nFilledLen += mHeaderOffset; ++ mWroteHeader = true; ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG; ++ notifyFillBufferDone(outHeader); ++ outInfo = NULL; ++ outHeader = NULL; ++ // get the next buffer for the rest of the data ++ CHECK(!outQueue.empty()); ++ outInfo = *outQueue.begin(); ++ outHeader = outInfo->mHeader; ++ } ++ ++ // write encoded data ++ ALOGV(" writing %zu bytes of encoded data on output port", bytes); ++ if (bytes > outHeader->nAllocLen - outHeader->nOffset - outHeader->nFilledLen) { ++ ALOGE(" not enough space left to write encoded data, dropping %zu bytes", bytes); ++ // a fatal error would stop the encoding ++ return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; ++ } ++ memcpy(outHeader->pBuffer + outHeader->nOffset, buffer, bytes); ++ ++ outHeader->nTimeStamp = mCurrentInputTimeStamp; ++ outHeader->nOffset = 0; ++ outHeader->nFilledLen += bytes; ++ outHeader->nFlags = 0; ++ ++ mEncoderReturnedEncodedData = true; ++ mEncoderReturnedNbBytes += bytes; ++ ++ return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; ++} ++ ++ ++OMX_ERRORTYPE SoftFlacEncoder::configureEncoder() { ++ ALOGV("SoftFlacEncoder::configureEncoder() numChannel=%d, sampleRate=%d", ++ mNumChannels, mSampleRate); ++ ++ if (mSignalledError || (mFlacStreamEncoder == NULL)) { ++ ALOGE("can't configure encoder: no encoder or invalid state"); ++ return OMX_ErrorInvalidState; ++ } ++ ++ const bool inputFloat = mNumericalData == OMX_NumericalDataFloat; ++ const int codecBitsPerSample = inputFloat ? 24 : 16; ++ FLAC__bool ok = true; ++ ok = ok && FLAC__stream_encoder_set_channels(mFlacStreamEncoder, mNumChannels); ++ ok = ok && FLAC__stream_encoder_set_sample_rate(mFlacStreamEncoder, mSampleRate); ++ ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, codecBitsPerSample); ++ ok = ok && FLAC__stream_encoder_set_compression_level(mFlacStreamEncoder, ++ (unsigned)mCompressionLevel); ++ ok = ok && FLAC__stream_encoder_set_verify(mFlacStreamEncoder, false); ++ if (!ok) { goto return_result; } ++ ++ ok &= FLAC__STREAM_ENCODER_INIT_STATUS_OK == ++ FLAC__stream_encoder_init_stream(mFlacStreamEncoder, ++ flacEncoderWriteCallback /*write_callback*/, ++ NULL /*seek_callback*/, ++ NULL /*tell_callback*/, ++ NULL /*metadata_callback*/, ++ (void *) this /*client_data*/); ++ ++return_result: ++ if (ok) { ++ ALOGV("encoder successfully configured"); ++ return OMX_ErrorNone; ++ } else { ++ ALOGE("unknown error when configuring encoder"); ++ return OMX_ErrorUndefined; ++ } ++} ++ ++ ++// static ++FLAC__StreamEncoderWriteStatus SoftFlacEncoder::flacEncoderWriteCallback( ++ const FLAC__StreamEncoder * /* encoder */, ++ const FLAC__byte buffer[], ++ size_t bytes, ++ unsigned samples, ++ unsigned current_frame, ++ void *client_data) { ++ return ((SoftFlacEncoder*) client_data)->onEncodedFlacAvailable( ++ buffer, bytes, samples, current_frame); ++} ++ ++} // namespace android ++ ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ return new android::SoftFlacEncoder(name, callbacks, appData, component); ++} ++ +diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h +new file mode 100644 +index 0000000..722fc13 +--- /dev/null ++++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h +@@ -0,0 +1,101 @@ ++/* ++ * Copyright (C) 2012 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 SOFT_FLAC_ENC_H_ ++ ++#define SOFT_FLAC_ENC_H_ ++ ++#include ++ ++#include "FLAC/stream_encoder.h" ++ ++namespace android { ++ ++struct SoftFlacEncoder : public SimpleSoftOMXComponent { ++ SoftFlacEncoder(const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++ virtual OMX_ERRORTYPE initCheck() const; ++ ++protected: ++ virtual ~SoftFlacEncoder(); ++ ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params); ++ ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ ++private: ++ const unsigned int kNumBuffers = 2; ++ static constexpr unsigned int kMaxChannels = 2; ++ static constexpr unsigned int kNumSamplesPerFrame = 1152; ++ static constexpr unsigned int kMaxInputBufferSize = ++ kNumSamplesPerFrame * kMaxChannels * sizeof(float); ++ const unsigned int kMaxOutputBufferSize = 65536; //TODO check if this can be reduced ++ ++ bool mSignalledError; ++ ++ OMX_U32 mNumChannels; ++ OMX_U32 mSampleRate; ++ OMX_U32 mCompressionLevel; ++ OMX_NUMERICALDATATYPE mNumericalData = OMX_NumericalDataSigned; ++ OMX_U32 mBitsPerSample = 16; ++ ++ // should the data received by the callback be written to the output port ++ bool mEncoderWriteData; ++ bool mEncoderReturnedEncodedData; ++ bool mSawInputEOS; ++ bool mSentOutputEOS; ++ size_t mEncoderReturnedNbBytes; ++ OMX_TICKS mCurrentInputTimeStamp; ++ ++ FLAC__StreamEncoder* mFlacStreamEncoder; ++ ++ void initPorts(); ++ ++ OMX_ERRORTYPE configureEncoder(); ++ ++ // FLAC encoder callbacks ++ // maps to encoderEncodeFlac() ++ static FLAC__StreamEncoderWriteStatus flacEncoderWriteCallback( ++ const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], ++ size_t bytes, unsigned samples, unsigned current_frame, void *client_data); ++ ++ FLAC__StreamEncoderWriteStatus onEncodedFlacAvailable( ++ const FLAC__byte buffer[], ++ size_t bytes, unsigned samples, unsigned current_frame); ++ ++ // FLAC takes samples aligned on 32bit boundaries, use this buffer for the conversion ++ // before passing the input data to the encoder ++ FLAC__int32* mInputBufferPcm32; ++ ++ unsigned mHeaderOffset; ++ bool mHeaderComplete; ++ bool mWroteHeader; ++ char mHeader[128]; ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftFlacEncoder); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_FLAC_ENC_H_ ++ +diff --git a/media/libstagefright/codecs/flac/enc/exports.lds b/media/libstagefright/codecs/flac/enc/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/flac/enc/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/g711/dec/Android.bp b/media/libstagefright/codecs/g711/dec/Android.bp +new file mode 100644 +index 0000000..1dc34c3 +--- /dev/null ++++ b/media/libstagefright/codecs/g711/dec/Android.bp +@@ -0,0 +1,35 @@ ++package { ++ default_applicable_licenses: [ ++ "frameworks_av_media_libstagefright_codecs_g711_dec_license", ++ ], ++} ++ ++// Added automatically by a large-scale-change ++// See: http://go/android-license-faq ++license { ++ name: "frameworks_av_media_libstagefright_codecs_g711_dec_license", ++ visibility: [":__subpackages__"], ++ license_kinds: [ ++ "SPDX-license-identifier-Apache-2.0", ++ ], ++ license_text: [ ++ "NOTICE", ++ ], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_g711dec", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: ["SoftG711.cpp"], ++ ++ version_script: "exports.lds", ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ "unsigned-integer-overflow", ++ ], ++ cfi: true, ++ }, ++} +diff --git a/media/libstagefright/codecs/g711/dec/MODULE_LICENSE_APACHE2 b/media/libstagefright/codecs/g711/dec/MODULE_LICENSE_APACHE2 +new file mode 100644 +index 0000000..e69de29 +diff --git a/media/libstagefright/codecs/g711/dec/NOTICE b/media/libstagefright/codecs/g711/dec/NOTICE +new file mode 100644 +index 0000000..c5b1efa +--- /dev/null ++++ b/media/libstagefright/codecs/g711/dec/NOTICE +@@ -0,0 +1,190 @@ ++ ++ Copyright (c) 2005-2008, 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. ++ ++ 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. ++ ++ ++ Apache License ++ Version 2.0, January 2004 ++ http://www.apache.org/licenses/ ++ ++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION ++ ++ 1. Definitions. ++ ++ "License" shall mean the terms and conditions for use, reproduction, ++ and distribution as defined by Sections 1 through 9 of this document. ++ ++ "Licensor" shall mean the copyright owner or entity authorized by ++ the copyright owner that is granting the License. ++ ++ "Legal Entity" shall mean the union of the acting entity and all ++ other entities that control, are controlled by, or are under common ++ control with that entity. For the purposes of this definition, ++ "control" means (i) the power, direct or indirect, to cause the ++ direction or management of such entity, whether by contract or ++ otherwise, or (ii) ownership of fifty percent (50%) or more of the ++ outstanding shares, or (iii) beneficial ownership of such entity. ++ ++ "You" (or "Your") shall mean an individual or Legal Entity ++ exercising permissions granted by this License. ++ ++ "Source" form shall mean the preferred form for making modifications, ++ including but not limited to software source code, documentation ++ source, and configuration files. ++ ++ "Object" form shall mean any form resulting from mechanical ++ transformation or translation of a Source form, including but ++ not limited to compiled object code, generated documentation, ++ and conversions to other media types. ++ ++ "Work" shall mean the work of authorship, whether in Source or ++ Object form, made available under the License, as indicated by a ++ copyright notice that is included in or attached to the work ++ (an example is provided in the Appendix below). ++ ++ "Derivative Works" shall mean any work, whether in Source or Object ++ form, that is based on (or derived from) the Work and for which the ++ editorial revisions, annotations, elaborations, or other modifications ++ represent, as a whole, an original work of authorship. For the purposes ++ of this License, Derivative Works shall not include works that remain ++ separable from, or merely link (or bind by name) to the interfaces of, ++ the Work and Derivative Works thereof. ++ ++ "Contribution" shall mean any work of authorship, including ++ the original version of the Work and any modifications or additions ++ to that Work or Derivative Works thereof, that is intentionally ++ submitted to Licensor for inclusion in the Work by the copyright owner ++ or by an individual or Legal Entity authorized to submit on behalf of ++ the copyright owner. For the purposes of this definition, "submitted" ++ means any form of electronic, verbal, or written communication sent ++ to the Licensor or its representatives, including but not limited to ++ communication on electronic mailing lists, source code control systems, ++ and issue tracking systems that are managed by, or on behalf of, the ++ Licensor for the purpose of discussing and improving the Work, but ++ excluding communication that is conspicuously marked or otherwise ++ designated in writing by the copyright owner as "Not a Contribution." ++ ++ "Contributor" shall mean Licensor and any individual or Legal Entity ++ on behalf of whom a Contribution has been received by Licensor and ++ subsequently incorporated within the Work. ++ ++ 2. Grant of Copyright License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ copyright license to reproduce, prepare Derivative Works of, ++ publicly display, publicly perform, sublicense, and distribute the ++ Work and such Derivative Works in Source or Object form. ++ ++ 3. Grant of Patent License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ (except as stated in this section) patent license to make, have made, ++ use, offer to sell, sell, import, and otherwise transfer the Work, ++ where such license applies only to those patent claims licensable ++ by such Contributor that are necessarily infringed by their ++ Contribution(s) alone or by combination of their Contribution(s) ++ with the Work to which such Contribution(s) was submitted. If You ++ institute patent litigation against any entity (including a ++ cross-claim or counterclaim in a lawsuit) alleging that the Work ++ or a Contribution incorporated within the Work constitutes direct ++ or contributory patent infringement, then any patent licenses ++ granted to You under this License for that Work shall terminate ++ as of the date such litigation is filed. ++ ++ 4. Redistribution. You may reproduce and distribute copies of the ++ Work or Derivative Works thereof in any medium, with or without ++ modifications, and in Source or Object form, provided that You ++ meet the following conditions: ++ ++ (a) You must give any other recipients of the Work or ++ Derivative Works a copy of this License; and ++ ++ (b) You must cause any modified files to carry prominent notices ++ stating that You changed the files; and ++ ++ (c) You must retain, in the Source form of any Derivative Works ++ that You distribute, all copyright, patent, trademark, and ++ attribution notices from the Source form of the Work, ++ excluding those notices that do not pertain to any part of ++ the Derivative Works; and ++ ++ (d) If the Work includes a "NOTICE" text file as part of its ++ distribution, then any Derivative Works that You distribute must ++ include a readable copy of the attribution notices contained ++ within such NOTICE file, excluding those notices that do not ++ pertain to any part of the Derivative Works, in at least one ++ of the following places: within a NOTICE text file distributed ++ as part of the Derivative Works; within the Source form or ++ documentation, if provided along with the Derivative Works; or, ++ within a display generated by the Derivative Works, if and ++ wherever such third-party notices normally appear. The contents ++ of the NOTICE file are for informational purposes only and ++ do not modify the License. You may add Your own attribution ++ notices within Derivative Works that You distribute, alongside ++ or as an addendum to the NOTICE text from the Work, provided ++ that such additional attribution notices cannot be construed ++ as modifying the License. ++ ++ You may add Your own copyright statement to Your modifications and ++ may provide additional or different license terms and conditions ++ for use, reproduction, or distribution of Your modifications, or ++ for any such Derivative Works as a whole, provided Your use, ++ reproduction, and distribution of the Work otherwise complies with ++ the conditions stated in this License. ++ ++ 5. Submission of Contributions. Unless You explicitly state otherwise, ++ any Contribution intentionally submitted for inclusion in the Work ++ by You to the Licensor shall be under the terms and conditions of ++ this License, without any additional terms or conditions. ++ Notwithstanding the above, nothing herein shall supersede or modify ++ the terms of any separate license agreement you may have executed ++ with Licensor regarding such Contributions. ++ ++ 6. Trademarks. This License does not grant permission to use the trade ++ names, trademarks, service marks, or product names of the Licensor, ++ except as required for reasonable and customary use in describing the ++ origin of the Work and reproducing the content of the NOTICE file. ++ ++ 7. Disclaimer of Warranty. Unless required by applicable law or ++ agreed to in writing, Licensor provides the Work (and each ++ Contributor provides its Contributions) on an "AS IS" BASIS, ++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or ++ implied, including, without limitation, any warranties or conditions ++ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A ++ PARTICULAR PURPOSE. You are solely responsible for determining the ++ appropriateness of using or redistributing the Work and assume any ++ risks associated with Your exercise of permissions under this License. ++ ++ 8. Limitation of Liability. In no event and under no legal theory, ++ whether in tort (including negligence), contract, or otherwise, ++ unless required by applicable law (such as deliberate and grossly ++ negligent acts) or agreed to in writing, shall any Contributor be ++ liable to You for damages, including any direct, indirect, special, ++ incidental, or consequential damages of any character arising as a ++ result of this License or out of the use or inability to use the ++ Work (including but not limited to damages for loss of goodwill, ++ work stoppage, computer failure or malfunction, or any and all ++ other commercial damages or losses), even if such Contributor ++ has been advised of the possibility of such damages. ++ ++ 9. Accepting Warranty or Additional Liability. While redistributing ++ the Work or Derivative Works thereof, You may choose to offer, ++ and charge a fee for, acceptance of support, warranty, indemnity, ++ or other liability obligations and/or rights consistent with this ++ License. However, in accepting such obligations, You may act only ++ on Your own behalf and on Your sole responsibility, not on behalf ++ of any other Contributor, and only if You agree to indemnify, ++ defend, and hold each Contributor harmless for any liability ++ incurred by, or claims asserted against, such Contributor by reason ++ of your accepting any such warranty or additional liability. ++ ++ END OF TERMS AND CONDITIONS ++ +diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.cpp b/media/libstagefright/codecs/g711/dec/SoftG711.cpp +new file mode 100644 +index 0000000..fe91510 +--- /dev/null ++++ b/media/libstagefright/codecs/g711/dec/SoftG711.cpp +@@ -0,0 +1,391 @@ ++/* ++ * Copyright (C) 2011 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 "SoftG711" ++#include ++ ++#include "SoftG711.h" ++ ++#include ++#include ++ ++#define MAX_CHANNEL_COUNT 6 /* maximum number of audio channels that can be decoded */ ++ ++namespace android { ++ ++template ++static void InitOMXParams(T *params) { ++ params->nSize = sizeof(T); ++ params->nVersion.s.nVersionMajor = 1; ++ params->nVersion.s.nVersionMinor = 0; ++ params->nVersion.s.nRevision = 0; ++ params->nVersion.s.nStep = 0; ++} ++ ++SoftG711::SoftG711( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SimpleSoftOMXComponent(name, callbacks, appData, component), ++ mIsMLaw(true), ++ mSignalledError(false), ++ mNumChannels(1), ++ mSamplingRate(8000) { ++ if (!strcmp(name, "OMX.google.g711.alaw.decoder")) { ++ mIsMLaw = false; ++ } else { ++ CHECK(!strcmp(name, "OMX.google.g711.mlaw.decoder")); ++ } ++ ++ initPorts(); ++} ++ ++SoftG711::~SoftG711() { ++} ++ ++void SoftG711::initPorts() { ++ OMX_PARAM_PORTDEFINITIONTYPE def; ++ InitOMXParams(&def); ++ ++ def.nPortIndex = 0; ++ def.eDir = OMX_DirInput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = 8192; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 1; ++ ++ def.format.audio.cMIMEType = ++ const_cast( ++ mIsMLaw ++ ? MEDIA_MIMETYPE_AUDIO_G711_MLAW ++ : MEDIA_MIMETYPE_AUDIO_G711_ALAW); ++ ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingG711; ++ ++ addPort(def); ++ ++ def.nPortIndex = 1; ++ def.eDir = OMX_DirOutput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = kMaxNumSamplesPerFrame * sizeof(int16_t); ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 2; ++ ++ def.format.audio.cMIMEType = const_cast("audio/raw"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; ++ ++ addPort(def); ++} ++ ++OMX_ERRORTYPE SoftG711::internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamAudioPortFormat: ++ { ++ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (formatParams->nIndex > 0) { ++ return OMX_ErrorNoMore; ++ } ++ ++ formatParams->eEncoding = ++ (formatParams->nPortIndex == 0) ++ ? OMX_AUDIO_CodingG711 : OMX_AUDIO_CodingPCM; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ pcmParams->eNumData = OMX_NumericalDataSigned; ++ pcmParams->eEndian = OMX_EndianBig; ++ pcmParams->bInterleaved = OMX_TRUE; ++ pcmParams->nBitPerSample = 16; ++ if (pcmParams->nPortIndex == 0) { ++ // input port ++ pcmParams->ePCMMode = mIsMLaw ? OMX_AUDIO_PCMModeMULaw ++ : OMX_AUDIO_PCMModeALaw; ++ } else { ++ // output port ++ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; ++ } ++ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; ++ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; ++ ++ pcmParams->nChannels = mNumChannels; ++ pcmParams->nSamplingRate = mSamplingRate; ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalGetParameter(index, params); ++ } ++} ++ ++OMX_ERRORTYPE SoftG711::internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 0 && pcmParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (pcmParams->nChannels < 1 || pcmParams->nChannels > MAX_CHANNEL_COUNT) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if(pcmParams->nPortIndex == 0) { ++ mNumChannels = pcmParams->nChannels; ++ } ++ ++ mSamplingRate = pcmParams->nSamplingRate; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPortFormat: ++ { ++ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if ((formatParams->nPortIndex == 0 ++ && formatParams->eEncoding != OMX_AUDIO_CodingG711) ++ || (formatParams->nPortIndex == 1 ++ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamStandardComponentRole: ++ { ++ const OMX_PARAM_COMPONENTROLETYPE *roleParams = ++ (const OMX_PARAM_COMPONENTROLETYPE *)params; ++ ++ if (!isValidOMXParam(roleParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (mIsMLaw) { ++ if (strncmp((const char *)roleParams->cRole, ++ "audio_decoder.g711mlaw", ++ OMX_MAX_STRINGNAME_SIZE - 1)) { ++ return OMX_ErrorUndefined; ++ } ++ } else { ++ if (strncmp((const char *)roleParams->cRole, ++ "audio_decoder.g711alaw", ++ OMX_MAX_STRINGNAME_SIZE - 1)) { ++ return OMX_ErrorUndefined; ++ } ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalSetParameter(index, params); ++ } ++} ++ ++void SoftG711::onQueueFilled(OMX_U32 /* portIndex */) { ++ if (mSignalledError) { ++ return; ++ } ++ ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ ++ while (!inQueue.empty() && !outQueue.empty()) { ++ BufferInfo *inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++ ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ ++ if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) { ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ ++ outHeader->nFilledLen = 0; ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ ++ outQueue.erase(outQueue.begin()); ++ outInfo->mOwnedByUs = false; ++ notifyFillBufferDone(outHeader); ++ return; ++ } ++ ++ if (inHeader->nFilledLen > kMaxNumSamplesPerFrame) { ++ ALOGE("input buffer too large (%d).", inHeader->nFilledLen); ++ ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ } ++ ++ if (inHeader->nFilledLen * sizeof(int16_t) > outHeader->nAllocLen) { ++ ALOGE("output buffer too small (%d).", outHeader->nAllocLen); ++ android_errorWriteLog(0x534e4554, "27793163"); ++ ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ const uint8_t *inputptr = inHeader->pBuffer + inHeader->nOffset; ++ ++ if (mIsMLaw) { ++ DecodeMLaw( ++ reinterpret_cast(outHeader->pBuffer), ++ inputptr, inHeader->nFilledLen); ++ } else { ++ DecodeALaw( ++ reinterpret_cast(outHeader->pBuffer), ++ inputptr, inHeader->nFilledLen); ++ } ++ ++ outHeader->nTimeStamp = inHeader->nTimeStamp; ++ outHeader->nOffset = 0; ++ outHeader->nFilledLen = inHeader->nFilledLen * sizeof(int16_t); ++ outHeader->nFlags = 0; ++ ++ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ inHeader->nFilledLen = 0; ++ } else { ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ } ++ ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ outInfo = NULL; ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ } ++} ++ ++// static ++void SoftG711::DecodeALaw( ++ int16_t *out, const uint8_t *in, size_t inSize) { ++ while (inSize > 0) { ++ inSize--; ++ int32_t x = *in++; ++ ++ int32_t ix = x ^ 0x55; ++ ix &= 0x7f; ++ ++ int32_t iexp = ix >> 4; ++ int32_t mant = ix & 0x0f; ++ ++ if (iexp > 0) { ++ mant += 16; ++ } ++ ++ mant = (mant << 4) + 8; ++ ++ if (iexp > 1) { ++ mant = mant << (iexp - 1); ++ } ++ ++ *out++ = (x > 127) ? mant : -mant; ++ } ++} ++ ++// static ++void SoftG711::DecodeMLaw( ++ int16_t *out, const uint8_t *in, size_t inSize) { ++ while (inSize > 0) { ++ inSize--; ++ int32_t x = *in++; ++ ++ int32_t mantissa = ~x; ++ int32_t exponent = (mantissa >> 4) & 7; ++ int32_t segment = exponent + 1; ++ mantissa &= 0x0f; ++ ++ int32_t step = 4 << segment; ++ ++ int32_t abs = (0x80L << exponent) + step * mantissa + step / 2 - 4 * 33; ++ ++ *out++ = (x < 0x80) ? -abs : abs; ++ } ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ return new android::SoftG711(name, callbacks, appData, component); ++} ++ +diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.h b/media/libstagefright/codecs/g711/dec/SoftG711.h +new file mode 100644 +index 0000000..3ece246 +--- /dev/null ++++ b/media/libstagefright/codecs/g711/dec/SoftG711.h +@@ -0,0 +1,64 @@ ++/* ++ * Copyright (C) 2011 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 SOFT_G711_H_ ++ ++#define SOFT_G711_H_ ++ ++#include ++ ++namespace android { ++ ++struct SoftG711 : public SimpleSoftOMXComponent { ++ SoftG711(const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++protected: ++ virtual ~SoftG711(); ++ ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params); ++ ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ ++private: ++ enum { ++ kNumBuffers = 4, ++ kMaxNumSamplesPerFrame = 16384, ++ }; ++ ++ bool mIsMLaw; ++ bool mSignalledError; ++ OMX_U32 mNumChannels; ++ int32_t mSamplingRate; ++ ++ void initPorts(); ++ ++ static void DecodeALaw(int16_t *out, const uint8_t *in, size_t inSize); ++ static void DecodeMLaw(int16_t *out, const uint8_t *in, size_t inSize); ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftG711); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_G711_H_ ++ +diff --git a/media/libstagefright/codecs/g711/dec/exports.lds b/media/libstagefright/codecs/g711/dec/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/g711/dec/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/gsm/dec/Android.bp b/media/libstagefright/codecs/gsm/dec/Android.bp +new file mode 100644 +index 0000000..efa2f83 +--- /dev/null ++++ b/media/libstagefright/codecs/gsm/dec/Android.bp +@@ -0,0 +1,37 @@ ++package { ++ default_applicable_licenses: [ ++ "frameworks_av_media_libstagefright_codecs_gsm_dec_license", ++ ], ++} ++ ++// Added automatically by a large-scale-change ++// See: http://go/android-license-faq ++license { ++ name: "frameworks_av_media_libstagefright_codecs_gsm_dec_license", ++ visibility: [":__subpackages__"], ++ license_kinds: [ ++ "SPDX-license-identifier-Apache-2.0", ++ ], ++ license_text: [ ++ "NOTICE", ++ ], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_gsmdec", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: ["SoftGSM.cpp"], ++ ++ version_script: "exports.lds", ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ "unsigned-integer-overflow", ++ ], ++ cfi: true, ++ }, ++ ++ static_libs: ["libgsm"], ++} +diff --git a/media/libstagefright/codecs/gsm/dec/MODULE_LICENSE_APACHE2 b/media/libstagefright/codecs/gsm/dec/MODULE_LICENSE_APACHE2 +new file mode 100644 +index 0000000..e69de29 +diff --git a/media/libstagefright/codecs/gsm/dec/NOTICE b/media/libstagefright/codecs/gsm/dec/NOTICE +new file mode 100644 +index 0000000..c5b1efa +--- /dev/null ++++ b/media/libstagefright/codecs/gsm/dec/NOTICE +@@ -0,0 +1,190 @@ ++ ++ Copyright (c) 2005-2008, 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. ++ ++ 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. ++ ++ ++ Apache License ++ Version 2.0, January 2004 ++ http://www.apache.org/licenses/ ++ ++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION ++ ++ 1. Definitions. ++ ++ "License" shall mean the terms and conditions for use, reproduction, ++ and distribution as defined by Sections 1 through 9 of this document. ++ ++ "Licensor" shall mean the copyright owner or entity authorized by ++ the copyright owner that is granting the License. ++ ++ "Legal Entity" shall mean the union of the acting entity and all ++ other entities that control, are controlled by, or are under common ++ control with that entity. For the purposes of this definition, ++ "control" means (i) the power, direct or indirect, to cause the ++ direction or management of such entity, whether by contract or ++ otherwise, or (ii) ownership of fifty percent (50%) or more of the ++ outstanding shares, or (iii) beneficial ownership of such entity. ++ ++ "You" (or "Your") shall mean an individual or Legal Entity ++ exercising permissions granted by this License. ++ ++ "Source" form shall mean the preferred form for making modifications, ++ including but not limited to software source code, documentation ++ source, and configuration files. ++ ++ "Object" form shall mean any form resulting from mechanical ++ transformation or translation of a Source form, including but ++ not limited to compiled object code, generated documentation, ++ and conversions to other media types. ++ ++ "Work" shall mean the work of authorship, whether in Source or ++ Object form, made available under the License, as indicated by a ++ copyright notice that is included in or attached to the work ++ (an example is provided in the Appendix below). ++ ++ "Derivative Works" shall mean any work, whether in Source or Object ++ form, that is based on (or derived from) the Work and for which the ++ editorial revisions, annotations, elaborations, or other modifications ++ represent, as a whole, an original work of authorship. For the purposes ++ of this License, Derivative Works shall not include works that remain ++ separable from, or merely link (or bind by name) to the interfaces of, ++ the Work and Derivative Works thereof. ++ ++ "Contribution" shall mean any work of authorship, including ++ the original version of the Work and any modifications or additions ++ to that Work or Derivative Works thereof, that is intentionally ++ submitted to Licensor for inclusion in the Work by the copyright owner ++ or by an individual or Legal Entity authorized to submit on behalf of ++ the copyright owner. For the purposes of this definition, "submitted" ++ means any form of electronic, verbal, or written communication sent ++ to the Licensor or its representatives, including but not limited to ++ communication on electronic mailing lists, source code control systems, ++ and issue tracking systems that are managed by, or on behalf of, the ++ Licensor for the purpose of discussing and improving the Work, but ++ excluding communication that is conspicuously marked or otherwise ++ designated in writing by the copyright owner as "Not a Contribution." ++ ++ "Contributor" shall mean Licensor and any individual or Legal Entity ++ on behalf of whom a Contribution has been received by Licensor and ++ subsequently incorporated within the Work. ++ ++ 2. Grant of Copyright License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ copyright license to reproduce, prepare Derivative Works of, ++ publicly display, publicly perform, sublicense, and distribute the ++ Work and such Derivative Works in Source or Object form. ++ ++ 3. Grant of Patent License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ (except as stated in this section) patent license to make, have made, ++ use, offer to sell, sell, import, and otherwise transfer the Work, ++ where such license applies only to those patent claims licensable ++ by such Contributor that are necessarily infringed by their ++ Contribution(s) alone or by combination of their Contribution(s) ++ with the Work to which such Contribution(s) was submitted. If You ++ institute patent litigation against any entity (including a ++ cross-claim or counterclaim in a lawsuit) alleging that the Work ++ or a Contribution incorporated within the Work constitutes direct ++ or contributory patent infringement, then any patent licenses ++ granted to You under this License for that Work shall terminate ++ as of the date such litigation is filed. ++ ++ 4. Redistribution. You may reproduce and distribute copies of the ++ Work or Derivative Works thereof in any medium, with or without ++ modifications, and in Source or Object form, provided that You ++ meet the following conditions: ++ ++ (a) You must give any other recipients of the Work or ++ Derivative Works a copy of this License; and ++ ++ (b) You must cause any modified files to carry prominent notices ++ stating that You changed the files; and ++ ++ (c) You must retain, in the Source form of any Derivative Works ++ that You distribute, all copyright, patent, trademark, and ++ attribution notices from the Source form of the Work, ++ excluding those notices that do not pertain to any part of ++ the Derivative Works; and ++ ++ (d) If the Work includes a "NOTICE" text file as part of its ++ distribution, then any Derivative Works that You distribute must ++ include a readable copy of the attribution notices contained ++ within such NOTICE file, excluding those notices that do not ++ pertain to any part of the Derivative Works, in at least one ++ of the following places: within a NOTICE text file distributed ++ as part of the Derivative Works; within the Source form or ++ documentation, if provided along with the Derivative Works; or, ++ within a display generated by the Derivative Works, if and ++ wherever such third-party notices normally appear. The contents ++ of the NOTICE file are for informational purposes only and ++ do not modify the License. You may add Your own attribution ++ notices within Derivative Works that You distribute, alongside ++ or as an addendum to the NOTICE text from the Work, provided ++ that such additional attribution notices cannot be construed ++ as modifying the License. ++ ++ You may add Your own copyright statement to Your modifications and ++ may provide additional or different license terms and conditions ++ for use, reproduction, or distribution of Your modifications, or ++ for any such Derivative Works as a whole, provided Your use, ++ reproduction, and distribution of the Work otherwise complies with ++ the conditions stated in this License. ++ ++ 5. Submission of Contributions. Unless You explicitly state otherwise, ++ any Contribution intentionally submitted for inclusion in the Work ++ by You to the Licensor shall be under the terms and conditions of ++ this License, without any additional terms or conditions. ++ Notwithstanding the above, nothing herein shall supersede or modify ++ the terms of any separate license agreement you may have executed ++ with Licensor regarding such Contributions. ++ ++ 6. Trademarks. This License does not grant permission to use the trade ++ names, trademarks, service marks, or product names of the Licensor, ++ except as required for reasonable and customary use in describing the ++ origin of the Work and reproducing the content of the NOTICE file. ++ ++ 7. Disclaimer of Warranty. Unless required by applicable law or ++ agreed to in writing, Licensor provides the Work (and each ++ Contributor provides its Contributions) on an "AS IS" BASIS, ++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or ++ implied, including, without limitation, any warranties or conditions ++ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A ++ PARTICULAR PURPOSE. You are solely responsible for determining the ++ appropriateness of using or redistributing the Work and assume any ++ risks associated with Your exercise of permissions under this License. ++ ++ 8. Limitation of Liability. In no event and under no legal theory, ++ whether in tort (including negligence), contract, or otherwise, ++ unless required by applicable law (such as deliberate and grossly ++ negligent acts) or agreed to in writing, shall any Contributor be ++ liable to You for damages, including any direct, indirect, special, ++ incidental, or consequential damages of any character arising as a ++ result of this License or out of the use or inability to use the ++ Work (including but not limited to damages for loss of goodwill, ++ work stoppage, computer failure or malfunction, or any and all ++ other commercial damages or losses), even if such Contributor ++ has been advised of the possibility of such damages. ++ ++ 9. Accepting Warranty or Additional Liability. While redistributing ++ the Work or Derivative Works thereof, You may choose to offer, ++ and charge a fee for, acceptance of support, warranty, indemnity, ++ or other liability obligations and/or rights consistent with this ++ License. However, in accepting such obligations, You may act only ++ on Your own behalf and on Your sole responsibility, not on behalf ++ of any other Contributor, and only if You agree to indemnify, ++ defend, and hold each Contributor harmless for any liability ++ incurred by, or claims asserted against, such Contributor by reason ++ of your accepting any such warranty or additional liability. ++ ++ END OF TERMS AND CONDITIONS ++ +diff --git a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp +new file mode 100644 +index 0000000..330cb8a +--- /dev/null ++++ b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp +@@ -0,0 +1,363 @@ ++/* ++ * Copyright (C) 2012 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 "SoftGSM" ++#include ++ ++#include "SoftGSM.h" ++ ++#include ++#include ++ ++namespace android { ++ ++template ++static void InitOMXParams(T *params) { ++ params->nSize = sizeof(T); ++ params->nVersion.s.nVersionMajor = 1; ++ params->nVersion.s.nVersionMinor = 0; ++ params->nVersion.s.nRevision = 0; ++ params->nVersion.s.nStep = 0; ++} ++ ++// Microsoft WAV GSM encoding packs two GSM frames into 65 bytes. ++static const int kMSGSMFrameSize = 65; ++ ++SoftGSM::SoftGSM( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SimpleSoftOMXComponent(name, callbacks, appData, component), ++ mSignalledError(false) { ++ ++ CHECK(!strcmp(name, "OMX.google.gsm.decoder")); ++ ++ mGsm = gsm_create(); ++ CHECK(mGsm); ++ int msopt = 1; ++ gsm_option(mGsm, GSM_OPT_WAV49, &msopt); ++ ++ initPorts(); ++} ++ ++SoftGSM::~SoftGSM() { ++ gsm_destroy(mGsm); ++} ++ ++void SoftGSM::initPorts() { ++ OMX_PARAM_PORTDEFINITIONTYPE def; ++ InitOMXParams(&def); ++ ++ def.nPortIndex = 0; ++ def.eDir = OMX_DirInput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = 1024 / kMSGSMFrameSize * kMSGSMFrameSize; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 1; ++ ++ def.format.audio.cMIMEType = ++ const_cast(MEDIA_MIMETYPE_AUDIO_MSGSM); ++ ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingGSMFR; ++ ++ addPort(def); ++ ++ def.nPortIndex = 1; ++ def.eDir = OMX_DirOutput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = kMaxNumSamplesPerFrame * sizeof(int16_t); ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 2; ++ ++ def.format.audio.cMIMEType = const_cast("audio/raw"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; ++ ++ addPort(def); ++} ++ ++OMX_ERRORTYPE SoftGSM::internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamAudioPortFormat: ++ { ++ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (formatParams->nIndex > 0) { ++ return OMX_ErrorNoMore; ++ } ++ ++ formatParams->eEncoding = ++ (formatParams->nPortIndex == 0) ++ ? OMX_AUDIO_CodingGSMFR : OMX_AUDIO_CodingPCM; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ pcmParams->eNumData = OMX_NumericalDataSigned; ++ pcmParams->eEndian = OMX_EndianBig; ++ pcmParams->bInterleaved = OMX_TRUE; ++ pcmParams->nBitPerSample = 16; ++ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; ++ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; ++ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; ++ ++ pcmParams->nChannels = 1; ++ pcmParams->nSamplingRate = 8000; ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalGetParameter(index, params); ++ } ++} ++ ++OMX_ERRORTYPE SoftGSM::internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 0 && pcmParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (pcmParams->nChannels != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (pcmParams->nSamplingRate != 8000) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPortFormat: ++ { ++ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if ((formatParams->nPortIndex == 0 ++ && formatParams->eEncoding != OMX_AUDIO_CodingGSMFR) ++ || (formatParams->nPortIndex == 1 ++ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamStandardComponentRole: ++ { ++ const OMX_PARAM_COMPONENTROLETYPE *roleParams = ++ (const OMX_PARAM_COMPONENTROLETYPE *)params; ++ ++ if (!isValidOMXParam(roleParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (strncmp((const char *)roleParams->cRole, ++ "audio_decoder.gsm", ++ OMX_MAX_STRINGNAME_SIZE - 1)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalSetParameter(index, params); ++ } ++} ++ ++void SoftGSM::onQueueFilled(OMX_U32 /* portIndex */) { ++ if (mSignalledError) { ++ return; ++ } ++ ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ ++ while (!inQueue.empty() && !outQueue.empty()) { ++ BufferInfo *inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++ ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ ++ if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) { ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ ++ outHeader->nFilledLen = 0; ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ ++ outQueue.erase(outQueue.begin()); ++ outInfo->mOwnedByUs = false; ++ notifyFillBufferDone(outHeader); ++ return; ++ } ++ ++ if (inHeader->nFilledLen > kMaxNumSamplesPerFrame) { ++ ALOGE("input buffer too large (%d).", inHeader->nFilledLen); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ } ++ ++ if(((inHeader->nFilledLen / kMSGSMFrameSize) * kMSGSMFrameSize) != inHeader->nFilledLen) { ++ ALOGE("input buffer not multiple of %d (%d).", kMSGSMFrameSize, inHeader->nFilledLen); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ } ++ ++ if (outHeader->nAllocLen < (inHeader->nFilledLen / kMSGSMFrameSize) * 320) { ++ ALOGE("output buffer is not large enough (%d).", outHeader->nAllocLen); ++ android_errorWriteLog(0x534e4554, "27793367"); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ uint8_t *inputptr = inHeader->pBuffer + inHeader->nOffset; ++ ++ int n = mSignalledError ? 0 : DecodeGSM(mGsm, ++ reinterpret_cast(outHeader->pBuffer), inputptr, inHeader->nFilledLen); ++ ++ outHeader->nTimeStamp = inHeader->nTimeStamp; ++ outHeader->nOffset = 0; ++ outHeader->nFilledLen = n * sizeof(int16_t); ++ outHeader->nFlags = 0; ++ ++ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ inHeader->nFilledLen = 0; ++ } else { ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ } ++ ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ outInfo = NULL; ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ } ++} ++ ++ ++// static ++int SoftGSM::DecodeGSM(gsm handle, ++ int16_t *out, uint8_t *in, size_t inSize) { ++ ++ int ret = 0; ++ while (inSize > 0) { ++ gsm_decode(handle, in, out); ++ in += 33; ++ inSize -= 33; ++ out += 160; ++ ret += 160; ++ gsm_decode(handle, in, out); ++ in += 32; ++ inSize -= 32; ++ out += 160; ++ ret += 160; ++ } ++ return ret; ++} ++ ++void SoftGSM::onPortFlushCompleted(OMX_U32 portIndex) { ++ if (portIndex == 0) { ++ gsm_destroy(mGsm); ++ mGsm = gsm_create(); ++ int msopt = 1; ++ gsm_option(mGsm, GSM_OPT_WAV49, &msopt); ++ } ++} ++ ++void SoftGSM::onReset() { ++ gsm_destroy(mGsm); ++ mGsm = gsm_create(); ++ int msopt = 1; ++ gsm_option(mGsm, GSM_OPT_WAV49, &msopt); ++ mSignalledError = false; ++} ++ ++ ++ ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ return new android::SoftGSM(name, callbacks, appData, component); ++} ++ +diff --git a/media/libstagefright/codecs/gsm/dec/SoftGSM.h b/media/libstagefright/codecs/gsm/dec/SoftGSM.h +new file mode 100644 +index 0000000..d5885a6 +--- /dev/null ++++ b/media/libstagefright/codecs/gsm/dec/SoftGSM.h +@@ -0,0 +1,66 @@ ++/* ++ * Copyright (C) 2012 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 SOFT_GSM_H_ ++ ++#define SOFT_GSM_H_ ++ ++#include ++ ++#include "gsm.h" ++ ++namespace android { ++ ++struct SoftGSM : public SimpleSoftOMXComponent { ++ SoftGSM(const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++protected: ++ virtual ~SoftGSM(); ++ ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params); ++ ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ ++ virtual void onPortFlushCompleted(OMX_U32 portIndex); ++ virtual void onReset(); ++ ++private: ++ enum { ++ kNumBuffers = 4, ++ kMaxNumSamplesPerFrame = 16384, ++ }; ++ ++ bool mSignalledError; ++ gsm mGsm; ++ ++ void initPorts(); ++ ++ static int DecodeGSM(gsm handle, int16_t *out, uint8_t *in, size_t inSize); ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftGSM); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_GSM_H_ ++ +diff --git a/media/libstagefright/codecs/gsm/dec/exports.lds b/media/libstagefright/codecs/gsm/dec/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/gsm/dec/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/hevcdec/Android.bp b/media/libstagefright/codecs/hevcdec/Android.bp +new file mode 100644 +index 0000000..2c4091b +--- /dev/null ++++ b/media/libstagefright/codecs/hevcdec/Android.bp +@@ -0,0 +1,38 @@ ++package { ++ // See: http://go/android-license-faq ++ // A large-scale-change added 'default_applicable_licenses' to import ++ // all of the 'license_kinds' from "frameworks_av_media_libstagefright_license" ++ // to get the below license kinds: ++ // SPDX-license-identifier-Apache-2.0 ++ default_applicable_licenses: ["frameworks_av_media_libstagefright_license"], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_hevcdec", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ static_libs: ["libhevcdec"], ++ srcs: ["SoftHEVC.cpp"], ++ ++ cflags: [ ++ "-Wall", ++ "-Wno-unused-variable", ++ ], ++ ++ version_script: "exports.lds", ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ ], ++ cfi: true, ++ config: { ++ cfi_assembly_support: true, ++ }, ++ }, ++ ++ // We need this because the current asm generates the following link error: ++ // requires unsupported dynamic reloc R_ARM_REL32; recompile with -fPIC ++ // Bug: 16853291 ++ ldflags: ["-Wl,-Bsymbolic"], ++} +diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp +new file mode 100644 +index 0000000..176da47 +--- /dev/null ++++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp +@@ -0,0 +1,726 @@ ++/* ++ * Copyright (C) 2014 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 "SoftHEVC" ++#include ++ ++#include "ihevc_typedefs.h" ++#include "iv.h" ++#include "ivd.h" ++#include "ihevcd_cxa.h" ++#include "SoftHEVC.h" ++ ++#include ++#include ++#include ++#include ++ ++namespace android { ++ ++#define componentName "video_decoder.hevc" ++#define codingType OMX_VIDEO_CodingHEVC ++#define CODEC_MIME_TYPE MEDIA_MIMETYPE_VIDEO_HEVC ++ ++/** Function and structure definitions to keep code similar for each codec */ ++#define ivdec_api_function ihevcd_cxa_api_function ++#define ivdext_create_ip_t ihevcd_cxa_create_ip_t ++#define ivdext_create_op_t ihevcd_cxa_create_op_t ++#define ivdext_delete_ip_t ihevcd_cxa_delete_ip_t ++#define ivdext_delete_op_t ihevcd_cxa_delete_op_t ++#define ivdext_ctl_set_num_cores_ip_t ihevcd_cxa_ctl_set_num_cores_ip_t ++#define ivdext_ctl_set_num_cores_op_t ihevcd_cxa_ctl_set_num_cores_op_t ++ ++#define IVDEXT_CMD_CTL_SET_NUM_CORES \ ++ (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES ++ ++static const CodecProfileLevel kProfileLevels[] = { ++ { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel51 }, ++ { OMX_VIDEO_HEVCProfileMainStill, OMX_VIDEO_HEVCMainTierLevel51 }, ++}; ++ ++SoftHEVC::SoftHEVC( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SoftVideoDecoderOMXComponent(name, componentName, codingType, ++ kProfileLevels, ARRAY_SIZE(kProfileLevels), ++ 320 /* width */, 240 /* height */, callbacks, ++ appData, component), ++ mCodecCtx(NULL), ++ mFlushOutBuffer(NULL), ++ mOmxColorFormat(OMX_COLOR_FormatYUV420Planar), ++ mIvColorFormat(IV_YUV_420P), ++ mChangingResolution(false), ++ mSignalledError(false), ++ mStride(mWidth) { ++ const size_t kMinCompressionRatio = 4 /* compressionRatio (for Level 4+) */; ++ const size_t kMaxOutputBufferSize = 2048 * 2048 * 3 / 2; ++ // INPUT_BUF_SIZE is given by HEVC codec as minimum input size ++ initPorts( ++ kNumBuffers, max(kMaxOutputBufferSize / kMinCompressionRatio, (size_t)INPUT_BUF_SIZE), ++ kNumBuffers, CODEC_MIME_TYPE, kMinCompressionRatio); ++} ++ ++status_t SoftHEVC::init() { ++ return initDecoder(); ++} ++ ++SoftHEVC::~SoftHEVC() { ++ ALOGV("In SoftHEVC::~SoftHEVC"); ++ CHECK_EQ(deInitDecoder(), (status_t)OK); ++} ++ ++static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) { ++ UNUSED(ctxt); ++ return memalign(alignment, size); ++} ++ ++static void ivd_aligned_free(void *ctxt, void *buf) { ++ UNUSED(ctxt); ++ free(buf); ++ return; ++} ++ ++static size_t GetCPUCoreCount() { ++ long cpuCoreCount = 1; ++#if defined(_SC_NPROCESSORS_ONLN) ++ cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); ++#else ++ // _SC_NPROC_ONLN must be defined... ++ cpuCoreCount = sysconf(_SC_NPROC_ONLN); ++#endif ++ CHECK(cpuCoreCount >= 1); ++ ALOGV("Number of CPU cores: %ld", cpuCoreCount); ++ return (size_t)cpuCoreCount; ++} ++ ++void SoftHEVC::logVersion() { ++ ivd_ctl_getversioninfo_ip_t s_ctl_ip; ++ ivd_ctl_getversioninfo_op_t s_ctl_op; ++ UWORD8 au1_buf[512]; ++ IV_API_CALL_STATUS_T status; ++ ++ s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION; ++ s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t); ++ s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t); ++ s_ctl_ip.pv_version_buffer = au1_buf; ++ s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf); ++ ++ status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, ++ (void *)&s_ctl_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGE("Error in getting version number: 0x%x", ++ s_ctl_op.u4_error_code); ++ } else { ++ ALOGV("Ittiam decoder version number: %s", ++ (char *)s_ctl_ip.pv_version_buffer); ++ } ++ return; ++} ++ ++status_t SoftHEVC::setParams(size_t stride) { ++ ivd_ctl_set_config_ip_t s_ctl_ip; ++ ivd_ctl_set_config_op_t s_ctl_op; ++ IV_API_CALL_STATUS_T status; ++ s_ctl_ip.u4_disp_wd = (UWORD32)stride; ++ s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE; ++ ++ s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT; ++ s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME; ++ s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS; ++ s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t); ++ s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t); ++ ++ ALOGV("Set the run-time (dynamic) parameters stride = %zu", stride); ++ status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, ++ (void *)&s_ctl_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGE("Error in setting the run-time parameters: 0x%x", ++ s_ctl_op.u4_error_code); ++ ++ return UNKNOWN_ERROR; ++ } ++ return OK; ++} ++ ++status_t SoftHEVC::resetPlugin() { ++ mIsInFlush = false; ++ mReceivedEOS = false; ++ memset(mTimeStamps, 0, sizeof(mTimeStamps)); ++ memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid)); ++ ++ /* Initialize both start and end times */ ++ gettimeofday(&mTimeStart, NULL); ++ gettimeofday(&mTimeEnd, NULL); ++ ++ return OK; ++} ++ ++bool SoftHEVC::getVUIParams() { ++ IV_API_CALL_STATUS_T status; ++ ihevcd_cxa_ctl_get_vui_params_ip_t s_ctl_get_vui_params_ip; ++ ihevcd_cxa_ctl_get_vui_params_op_t s_ctl_get_vui_params_op; ++ ++ s_ctl_get_vui_params_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_ctl_get_vui_params_ip.e_sub_cmd = ++ (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_GET_VUI_PARAMS; ++ ++ s_ctl_get_vui_params_ip.u4_size = ++ sizeof(ihevcd_cxa_ctl_get_vui_params_ip_t); ++ ++ s_ctl_get_vui_params_op.u4_size = sizeof(ihevcd_cxa_ctl_get_vui_params_op_t); ++ ++ status = ivdec_api_function( ++ (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_vui_params_ip, ++ (void *)&s_ctl_get_vui_params_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGW("Error in getting VUI params: 0x%x", ++ s_ctl_get_vui_params_op.u4_error_code); ++ return false; ++ } ++ ++ int32_t primaries = s_ctl_get_vui_params_op.u1_colour_primaries; ++ int32_t transfer = s_ctl_get_vui_params_op.u1_transfer_characteristics; ++ int32_t coeffs = s_ctl_get_vui_params_op.u1_matrix_coefficients; ++ bool fullRange = s_ctl_get_vui_params_op.u1_video_full_range_flag; ++ ++ ColorAspects colorAspects; ++ ColorUtils::convertIsoColorAspectsToCodecAspects( ++ primaries, transfer, coeffs, fullRange, colorAspects); ++ ++ // Update color aspects if necessary. ++ if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) { ++ mBitstreamColorAspects = colorAspects; ++ status_t err = handleColorAspectsChange(); ++ CHECK(err == OK); ++ } ++ return true; ++} ++ ++status_t SoftHEVC::resetDecoder() { ++ ivd_ctl_reset_ip_t s_ctl_ip; ++ ivd_ctl_reset_op_t s_ctl_op; ++ IV_API_CALL_STATUS_T status; ++ ++ s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET; ++ s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t); ++ s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t); ++ ++ status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, ++ (void *)&s_ctl_op); ++ if (IV_SUCCESS != status) { ++ ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code); ++ return UNKNOWN_ERROR; ++ } ++ mSignalledError = false; ++ ++ /* Set number of cores/threads to be used by the codec */ ++ setNumCores(); ++ ++ mStride = 0; ++ return OK; ++} ++ ++status_t SoftHEVC::setNumCores() { ++ ivdext_ctl_set_num_cores_ip_t s_set_cores_ip; ++ ivdext_ctl_set_num_cores_op_t s_set_cores_op; ++ IV_API_CALL_STATUS_T status; ++ s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES; ++ s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES); ++ s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t); ++ s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t); ++ ALOGV("Set number of cores to %u", s_set_cores_ip.u4_num_cores); ++ status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip, ++ (void *)&s_set_cores_op); ++ if (IV_SUCCESS != status) { ++ ALOGE("Error in setting number of cores: 0x%x", ++ s_set_cores_op.u4_error_code); ++ return UNKNOWN_ERROR; ++ } ++ return OK; ++} ++ ++status_t SoftHEVC::setFlushMode() { ++ IV_API_CALL_STATUS_T status; ++ ivd_ctl_flush_ip_t s_video_flush_ip; ++ ivd_ctl_flush_op_t s_video_flush_op; ++ ++ s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH; ++ s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t); ++ s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t); ++ ALOGV("Set the decoder in flush mode "); ++ ++ /* Set the decoder in Flush mode, subsequent decode() calls will flush */ ++ status = ivdec_api_function(mCodecCtx, (void *)&s_video_flush_ip, ++ (void *)&s_video_flush_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status, ++ s_video_flush_op.u4_error_code); ++ return UNKNOWN_ERROR; ++ } ++ ++ mIsInFlush = true; ++ return OK; ++} ++ ++status_t SoftHEVC::initDecoder() { ++ IV_API_CALL_STATUS_T status; ++ ++ mNumCores = GetCPUCoreCount(); ++ mCodecCtx = NULL; ++ ++ mStride = outputBufferWidth(); ++ ++ /* Initialize the decoder */ ++ { ++ ivdext_create_ip_t s_create_ip; ++ ivdext_create_op_t s_create_op; ++ ++ void *dec_fxns = (void *)ivdec_api_function; ++ ++ s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t); ++ s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE; ++ s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0; ++ s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t); ++ s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat; ++ s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc; ++ s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free; ++ s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL; ++ ++ status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGE("Error in create: 0x%x", ++ s_create_op.s_ivd_create_op_t.u4_error_code); ++ deInitDecoder(); ++ mCodecCtx = NULL; ++ return UNKNOWN_ERROR; ++ } ++ ++ mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle; ++ mCodecCtx->pv_fxns = dec_fxns; ++ mCodecCtx->u4_size = sizeof(iv_obj_t); ++ } ++ ++ /* Reset the plugin state */ ++ resetPlugin(); ++ ++ /* Set the run time (dynamic) parameters */ ++ setParams(mStride); ++ ++ /* Set number of cores/threads to be used by the codec */ ++ setNumCores(); ++ ++ /* Get codec version */ ++ logVersion(); ++ ++ mFlushNeeded = false; ++ return OK; ++} ++ ++status_t SoftHEVC::deInitDecoder() { ++ size_t i; ++ IV_API_CALL_STATUS_T status; ++ ++ if (mCodecCtx) { ++ ivdext_delete_ip_t s_delete_ip; ++ ivdext_delete_op_t s_delete_op; ++ ++ s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t); ++ s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE; ++ ++ s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t); ++ ++ status = ivdec_api_function(mCodecCtx, (void *)&s_delete_ip, (void *)&s_delete_op); ++ if (status != IV_SUCCESS) { ++ ALOGE("Error in delete: 0x%x", ++ s_delete_op.s_ivd_delete_op_t.u4_error_code); ++ return UNKNOWN_ERROR; ++ } ++ } ++ ++ ++ mChangingResolution = false; ++ ++ return OK; ++} ++ ++void SoftHEVC::onReset() { ++ ALOGV("onReset called"); ++ SoftVideoDecoderOMXComponent::onReset(); ++ ++ mSignalledError = false; ++ resetDecoder(); ++ resetPlugin(); ++} ++ ++bool SoftHEVC::setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip, ++ ivd_video_decode_op_t *ps_dec_op, ++ OMX_BUFFERHEADERTYPE *inHeader, ++ OMX_BUFFERHEADERTYPE *outHeader, ++ size_t timeStampIx) { ++ size_t sizeY = outputBufferWidth() * outputBufferHeight(); ++ size_t sizeUV; ++ ++ ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t); ++ ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t); ++ ++ ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE; ++ ++ /* When in flush and after EOS with zero byte input, ++ * inHeader is set to zero. Hence check for non-null */ ++ if (inHeader) { ++ ps_dec_ip->u4_ts = timeStampIx; ++ ps_dec_ip->pv_stream_buffer = inHeader->pBuffer ++ + inHeader->nOffset; ++ ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen; ++ } else { ++ ps_dec_ip->u4_ts = 0; ++ ps_dec_ip->pv_stream_buffer = NULL; ++ ps_dec_ip->u4_num_Bytes = 0; ++ } ++ ++ sizeUV = sizeY / 4; ++ ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY; ++ ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV; ++ ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV; ++ ++ uint8_t *pBuf; ++ if (outHeader) { ++ if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) { ++ android_errorWriteLog(0x534e4554, "27833616"); ++ return false; ++ } ++ pBuf = outHeader->pBuffer; ++ } else { ++ // mFlushOutBuffer always has the right size. ++ pBuf = mFlushOutBuffer; ++ } ++ ++ ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf; ++ ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY; ++ ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV; ++ ps_dec_ip->s_out_buffer.u4_num_bufs = 3; ++ return true; ++} ++void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) { ++ /* Once the output buffers are flushed, ignore any buffers that are held in decoder */ ++ if (kOutputPortIndex == portIndex) { ++ setFlushMode(); ++ ++ /* Allocate a picture buffer to flushed data */ ++ uint32_t displayStride = outputBufferWidth(); ++ uint32_t displayHeight = outputBufferHeight(); ++ ++ uint32_t bufferSize = displayStride * displayHeight * 3 / 2; ++ mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize); ++ if (NULL == mFlushOutBuffer) { ++ ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize); ++ return; ++ } ++ ++ while (true) { ++ ivd_video_decode_ip_t s_dec_ip; ++ ivd_video_decode_op_t s_dec_op; ++ IV_API_CALL_STATUS_T status; ++ size_t sizeY, sizeUV; ++ ++ setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0); ++ ++ status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, ++ (void *)&s_dec_op); ++ if (0 == s_dec_op.u4_output_present) { ++ resetPlugin(); ++ break; ++ } ++ } ++ ++ if (mFlushOutBuffer) { ++ free(mFlushOutBuffer); ++ mFlushOutBuffer = NULL; ++ } ++ ++ } ++} ++ ++void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { ++ UNUSED(portIndex); ++ ++ if (mSignalledError) { ++ return; ++ } ++ if (mOutputPortSettingsChange != NONE) { ++ return; ++ } ++ ++ if (NULL == mCodecCtx) { ++ if (OK != initDecoder()) { ++ ALOGE("Failed to initialize decoder"); ++ notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ } ++ if (outputBufferWidth() != mStride) { ++ /* Set the run-time (dynamic) parameters */ ++ mStride = outputBufferWidth(); ++ setParams(mStride); ++ } ++ ++ List &inQueue = getPortQueue(kInputPortIndex); ++ List &outQueue = getPortQueue(kOutputPortIndex); ++ ++ while (!outQueue.empty()) { ++ BufferInfo *inInfo; ++ OMX_BUFFERHEADERTYPE *inHeader; ++ ++ BufferInfo *outInfo; ++ OMX_BUFFERHEADERTYPE *outHeader; ++ size_t timeStampIx; ++ ++ inInfo = NULL; ++ inHeader = NULL; ++ ++ if (!mIsInFlush) { ++ if (!inQueue.empty()) { ++ inInfo = *inQueue.begin(); ++ inHeader = inInfo->mHeader; ++ } else { ++ break; ++ } ++ } ++ ++ outInfo = *outQueue.begin(); ++ outHeader = outInfo->mHeader; ++ outHeader->nFlags = 0; ++ outHeader->nTimeStamp = 0; ++ outHeader->nOffset = 0; ++ ++ if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) { ++ mReceivedEOS = true; ++ if (inHeader->nFilledLen == 0) { ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ setFlushMode(); ++ } ++ } ++ ++ /* Get a free slot in timestamp array to hold input timestamp */ ++ { ++ size_t i; ++ timeStampIx = 0; ++ for (i = 0; i < MAX_TIME_STAMPS; i++) { ++ if (!mTimeStampsValid[i]) { ++ timeStampIx = i; ++ break; ++ } ++ } ++ if (inHeader != NULL) { ++ mTimeStampsValid[timeStampIx] = true; ++ mTimeStamps[timeStampIx] = inHeader->nTimeStamp; ++ } ++ } ++ ++ { ++ ivd_video_decode_ip_t s_dec_ip; ++ ivd_video_decode_op_t s_dec_op; ++ WORD32 timeDelay, timeTaken; ++ size_t sizeY, sizeUV; ++ ++ if (!setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) { ++ ALOGE("Decoder arg setup failed"); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ GETTIME(&mTimeStart, NULL); ++ /* Compute time elapsed between end of previous decode() ++ * to start of current decode() */ ++ TIME_DIFF(mTimeEnd, mTimeStart, timeDelay); ++ ++ IV_API_CALL_STATUS_T status; ++ status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); ++ ++ bool unsupportedResolution = ++ (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_dec_op.u4_error_code & IVD_ERROR_MASK)); ++ ++ /* Check for unsupported dimensions */ ++ if (unsupportedResolution) { ++ ALOGE("Unsupported resolution : %dx%d", mWidth, mHeight); ++ notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ bool allocationFailed = ++ (IVD_MEM_ALLOC_FAILED == (s_dec_op.u4_error_code & IVD_ERROR_MASK)); ++ if (allocationFailed) { ++ ALOGE("Allocation failure in decoder"); ++ notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ if (IS_IVD_FATAL_ERROR(s_dec_op.u4_error_code)) { ++ ALOGE("Fatal Error : 0x%x", s_dec_op.u4_error_code); ++ notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & IVD_ERROR_MASK)); ++ ++ getVUIParams(); ++ ++ GETTIME(&mTimeEnd, NULL); ++ /* Compute time taken for decode() */ ++ TIME_DIFF(mTimeStart, mTimeEnd, timeTaken); ++ ++ ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, ++ s_dec_op.u4_num_bytes_consumed); ++ if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) { ++ mFlushNeeded = true; ++ } ++ ++ if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) { ++ /* If the input did not contain picture data, then ignore ++ * the associated timestamp */ ++ mTimeStampsValid[timeStampIx] = false; ++ } ++ ++ // If the decoder is in the changing resolution mode and there is no output present, ++ // that means the switching is done and it's ready to reset the decoder and the plugin. ++ if (mChangingResolution && !s_dec_op.u4_output_present) { ++ mChangingResolution = false; ++ resetDecoder(); ++ resetPlugin(); ++ mStride = outputBufferWidth(); ++ setParams(mStride); ++ continue; ++ } ++ ++ if (resChanged) { ++ mChangingResolution = true; ++ if (mFlushNeeded) { ++ setFlushMode(); ++ } ++ continue; ++ } ++ ++ // Combine the resolution change and coloraspects change in one PortSettingChange event ++ // if necessary. ++ if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) { ++ uint32_t width = s_dec_op.u4_pic_wd; ++ uint32_t height = s_dec_op.u4_pic_ht; ++ bool portWillReset = false; ++ handlePortSettingsChange(&portWillReset, width, height); ++ ++ if (portWillReset) { ++ resetDecoder(); ++ resetPlugin(); ++ return; ++ } ++ } else if (mUpdateColorAspects) { ++ notify(OMX_EventPortSettingsChanged, kOutputPortIndex, ++ kDescribeColorAspectsIndex, NULL); ++ mUpdateColorAspects = false; ++ return; ++ } ++ ++ if (s_dec_op.u4_output_present) { ++ outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2; ++ ++ outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts]; ++ mTimeStampsValid[s_dec_op.u4_ts] = false; ++ ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ outInfo = NULL; ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ } else if (mIsInFlush) { ++ /* If in flush mode and no output is returned by the codec, ++ * then come out of flush mode */ ++ mIsInFlush = false; ++ ++ /* If EOS was recieved on input port and there is no output ++ * from the codec, then signal EOS on output port */ ++ if (mReceivedEOS) { ++ outHeader->nFilledLen = 0; ++ outHeader->nFlags |= OMX_BUFFERFLAG_EOS; ++ ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ outInfo = NULL; ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ resetPlugin(); ++ } ++ } ++ } ++ ++ /* If input EOS is seen and decoder is not in flush mode, ++ * set the decoder in flush mode. ++ * There can be a case where EOS is sent along with last picture data ++ * In that case, only after decoding that input data, decoder has to be ++ * put in flush. This case is handled here */ ++ ++ if (mReceivedEOS && !mIsInFlush) { ++ setFlushMode(); ++ } ++ ++ // TODO: Handle more than one picture data ++ if (inHeader != NULL) { ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ } ++ } ++} ++ ++int SoftHEVC::getColorAspectPreference() { ++ return kPreferBitstream; ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent(const char *name, ++ const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) { ++ android::SoftHEVC *codec = new android::SoftHEVC(name, callbacks, appData, component); ++ if (codec->init() != android::OK) { ++ android::sp release = codec; ++ return NULL; ++ } ++ return codec; ++} +diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.h b/media/libstagefright/codecs/hevcdec/SoftHEVC.h +new file mode 100644 +index 0000000..5800490 +--- /dev/null ++++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.h +@@ -0,0 +1,123 @@ ++/* ++ * Copyright (C) 2014 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 SOFT_HEVC_H_ ++ ++#define SOFT_HEVC_H_ ++ ++#include ++#include ++ ++namespace android { ++ ++/** Number of entries in the time-stamp array */ ++#define MAX_TIME_STAMPS 64 ++ ++/** Maximum number of cores supported by the codec */ ++#define CODEC_MAX_NUM_CORES 4 ++ ++#define CODEC_MAX_WIDTH 1920 ++ ++#define CODEC_MAX_HEIGHT 1088 ++ ++/** Input buffer size */ ++#define INPUT_BUF_SIZE (1024 * 1024) ++ ++#define MIN(a, b) ((a) < (b)) ? (a) : (b) ++ ++/** Used to remove warnings about unused parameters */ ++#define UNUSED(x) ((void)(x)) ++ ++/** Get time */ ++#define GETTIME(a, b) gettimeofday(a, b); ++ ++/** Compute difference between start and end */ ++#define TIME_DIFF(start, end, diff) \ ++ diff = (((end).tv_sec - (start).tv_sec) * 1000000) + \ ++ ((end).tv_usec - (start).tv_usec); ++ ++struct SoftHEVC: public SoftVideoDecoderOMXComponent { ++ SoftHEVC(const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component); ++ ++ status_t init(); ++ ++protected: ++ virtual ~SoftHEVC(); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ virtual void onPortFlushCompleted(OMX_U32 portIndex); ++ virtual void onReset(); ++ virtual int getColorAspectPreference(); ++private: ++ // Number of input and output buffers ++ enum { ++ kNumBuffers = 8 ++ }; ++ ++ iv_obj_t *mCodecCtx; // Codec context ++ ++ size_t mNumCores; // Number of cores to be uesd by the codec ++ ++ struct timeval mTimeStart; // Time at the start of decode() ++ struct timeval mTimeEnd; // Time at the end of decode() ++ ++ // Internal buffer to be used to flush out the buffers from decoder ++ uint8_t *mFlushOutBuffer; ++ ++ // Status of entries in the timestamp array ++ bool mTimeStampsValid[MAX_TIME_STAMPS]; ++ ++ // Timestamp array - Since codec does not take 64 bit timestamps, ++ // they are maintained in the plugin ++ OMX_S64 mTimeStamps[MAX_TIME_STAMPS]; ++ ++ OMX_COLOR_FORMATTYPE mOmxColorFormat; // OMX Color format ++ IV_COLOR_FORMAT_T mIvColorFormat; // Ittiam Color format ++ ++ bool mIsInFlush; // codec is flush mode ++ bool mReceivedEOS; // EOS is receieved on input port ++ ++ // The input stream has changed to a different resolution, which is still supported by the ++ // codec. So the codec is switching to decode the new resolution. ++ bool mChangingResolution; ++ bool mFlushNeeded; ++ bool mSignalledError; ++ size_t mStride; ++ ++ status_t initDecoder(); ++ status_t deInitDecoder(); ++ status_t setFlushMode(); ++ status_t setParams(size_t stride); ++ void logVersion(); ++ status_t setNumCores(); ++ status_t resetDecoder(); ++ status_t resetPlugin(); ++ ++ bool setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip, ++ ivd_video_decode_op_t *ps_dec_op, ++ OMX_BUFFERHEADERTYPE *inHeader, ++ OMX_BUFFERHEADERTYPE *outHeader, ++ size_t timeStampIx); ++ ++ bool getVUIParams(); ++ ++ DISALLOW_EVIL_CONSTRUCTORS (SoftHEVC); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_HEVC_H_ +diff --git a/media/libstagefright/codecs/hevcdec/exports.lds b/media/libstagefright/codecs/hevcdec/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/hevcdec/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.bp b/media/libstagefright/codecs/m4v_h263/dec/Android.bp +new file mode 100644 +index 0000000..725c79c +--- /dev/null ++++ b/media/libstagefright/codecs/m4v_h263/dec/Android.bp +@@ -0,0 +1,28 @@ ++ ++package { ++ // See: http://go/android-license-faq ++ // A large-scale-change added 'default_applicable_licenses' to import ++ // all of the 'license_kinds' from "frameworks_av_media_libstagefright_license" ++ // to get the below license kinds: ++ // SPDX-license-identifier-Apache-2.0 ++ default_applicable_licenses: ["frameworks_av_media_libstagefright_license"], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_mpeg4dec", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: ["SoftMPEG4.cpp"], ++ ++ cflags: [ ++ ], ++ ++ static_libs: ["libstagefright_m4vh263dec"], ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ ], ++ cfi: true, ++ }, ++} +diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp +new file mode 100644 +index 0000000..800e2e1 +--- /dev/null ++++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp +@@ -0,0 +1,440 @@ ++/* ++ * Copyright (C) 2011 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 "SoftMPEG4" ++#include ++ ++#include "SoftMPEG4.h" ++ ++#include ++#include ++#include ++#include ++ ++#include "mp4dec_api.h" ++ ++namespace android { ++ ++static const CodecProfileLevel kM4VProfileLevels[] = { ++ { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3 }, ++}; ++ ++static const CodecProfileLevel kH263ProfileLevels[] = { ++ { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level30 }, ++ { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level45 }, ++ { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level30 }, ++ { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level45 }, ++}; ++ ++SoftMPEG4::SoftMPEG4( ++ const char *name, ++ const char *componentRole, ++ OMX_VIDEO_CODINGTYPE codingType, ++ const CodecProfileLevel *profileLevels, ++ size_t numProfileLevels, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SoftVideoDecoderOMXComponent( ++ name, componentRole, codingType, profileLevels, numProfileLevels, ++ 352 /* width */, 288 /* height */, callbacks, appData, component), ++ mMode(codingType == OMX_VIDEO_CodingH263 ? MODE_H263 : MODE_MPEG4), ++ mHandle(new tagvideoDecControls), ++ mInputBufferCount(0), ++ mSignalledError(false), ++ mInitialized(false), ++ mFramesConfigured(false), ++ mNumSamplesOutput(0), ++ mPvTime(0) { ++ initPorts( ++ kNumInputBuffers, ++ 352 * 288 * 3 / 2 /* minInputBufferSize */, ++ kNumOutputBuffers, ++ (mMode == MODE_MPEG4) ++ ? MEDIA_MIMETYPE_VIDEO_MPEG4 : MEDIA_MIMETYPE_VIDEO_H263); ++ CHECK_EQ(initDecoder(), (status_t)OK); ++} ++ ++SoftMPEG4::~SoftMPEG4() { ++ if (mInitialized) { ++ PVCleanUpVideoDecoder(mHandle); ++ } ++ ++ delete mHandle; ++ mHandle = NULL; ++} ++ ++status_t SoftMPEG4::initDecoder() { ++ memset(mHandle, 0, sizeof(tagvideoDecControls)); ++ return OK; ++} ++ ++void SoftMPEG4::onQueueFilled(OMX_U32 /* portIndex */) { ++ if (mSignalledError || mOutputPortSettingsChange != NONE) { ++ return; ++ } ++ ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ ++ while (!inQueue.empty() && outQueue.size() == kNumOutputBuffers) { ++ BufferInfo *inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++ if (inHeader == NULL) { ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ continue; ++ } ++ ++ PortInfo *port = editPortInfo(1); ++ ++ OMX_BUFFERHEADERTYPE *outHeader = ++ port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader; ++ ++ if (inHeader->nFilledLen == 0) { ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ ++ ++mInputBufferCount; ++ ++ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ outHeader->nFilledLen = 0; ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ ++ List::iterator it = outQueue.begin(); ++ while (it != outQueue.end() && (*it)->mHeader != outHeader) { ++ ++it; ++ } ++ if (it == outQueue.end()) { ++ ALOGE("couldn't find port buffer %d in outQueue: b/109891727", mNumSamplesOutput & 1); ++ android_errorWriteLog(0x534e4554, "109891727"); ++ return; ++ } ++ ++ BufferInfo *outInfo = *it; ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(it); ++ outInfo = NULL; ++ ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ } ++ return; ++ } ++ ++ uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset; ++ uint32_t *start_code = (uint32_t *)bitstream; ++ bool volHeader = *start_code == 0xB0010000; ++ if (volHeader) { ++ PVCleanUpVideoDecoder(mHandle); ++ mInitialized = false; ++ } ++ ++ if (!mInitialized) { ++ uint8_t *vol_data[1]; ++ int32_t vol_size = 0; ++ ++ vol_data[0] = NULL; ++ ++ if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) || volHeader) { ++ vol_data[0] = bitstream; ++ vol_size = inHeader->nFilledLen; ++ } ++ ++ MP4DecodingMode mode = ++ (mMode == MODE_MPEG4) ? MPEG4_MODE : H263_MODE; ++ ++ Bool success = PVInitVideoDecoder( ++ mHandle, vol_data, &vol_size, 1, ++ outputBufferWidth(), outputBufferHeight(), mode); ++ ++ if (!success) { ++ ALOGW("PVInitVideoDecoder failed. Unsupported content?"); ++ ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle); ++ if (mode != actualMode) { ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ PVSetPostProcType((VideoDecControls *) mHandle, 0); ++ ++ bool hasFrameData = false; ++ if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ } else if (volHeader) { ++ hasFrameData = true; ++ } ++ ++ mInitialized = true; ++ ++ if (mode == MPEG4_MODE && handlePortSettingsChange()) { ++ return; ++ } ++ ++ if (!hasFrameData) { ++ continue; ++ } ++ } ++ ++ if (!mFramesConfigured) { ++ PortInfo *port = editPortInfo(1); ++ OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader; ++ ++ OMX_U32 yFrameSize = sizeof(uint8) * mHandle->size; ++ if ((outHeader->nAllocLen < yFrameSize) || ++ (outHeader->nAllocLen - yFrameSize < yFrameSize / 2)) { ++ ALOGE("Too small output buffer for reference frame: %lu bytes", ++ (unsigned long)outHeader->nAllocLen); ++ android_errorWriteLog(0x534e4554, "30033990"); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ PVSetReferenceYUV(mHandle, outHeader->pBuffer); ++ mFramesConfigured = true; ++ } ++ ++ uint32_t useExtTimestamp = (inHeader->nOffset == 0); ++ ++ // decoder deals in ms (int32_t), OMX in us (int64_t) ++ // so use fake timestamp instead ++ uint32_t timestamp = 0xFFFFFFFF; ++ if (useExtTimestamp) { ++ mPvToOmxTimeMap.add(mPvTime, inHeader->nTimeStamp); ++ timestamp = mPvTime; ++ mPvTime++; ++ } ++ ++ int32_t bufferSize = inHeader->nFilledLen; ++ int32_t tmp = bufferSize; ++ ++ OMX_U32 frameSize; ++ OMX_U64 yFrameSize = (OMX_U64)mWidth * (OMX_U64)mHeight; ++ if (yFrameSize > ((OMX_U64)UINT32_MAX / 3) * 2) { ++ ALOGE("Frame size too large"); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ frameSize = (OMX_U32)(yFrameSize + (yFrameSize / 2)); ++ ++ if (outHeader->nAllocLen < frameSize) { ++ android_errorWriteLog(0x534e4554, "27833616"); ++ ALOGE("Insufficient output buffer size"); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ // Need to check if header contains new info, e.g., width/height, etc. ++ VopHeaderInfo header_info; ++ uint8_t *bitstreamTmp = bitstream; ++ if (PVDecodeVopHeader( ++ mHandle, &bitstreamTmp, ×tamp, &tmp, ++ &header_info, &useExtTimestamp, ++ outHeader->pBuffer) != PV_TRUE) { ++ ALOGE("failed to decode vop header."); ++ ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ if (handlePortSettingsChange()) { ++ return; ++ } ++ ++ // The PV decoder is lying to us, sometimes it'll claim to only have ++ // consumed a subset of the buffer when it clearly consumed all of it. ++ // ignore whatever it says... ++ if (PVDecodeVopBody(mHandle, &tmp) != PV_TRUE) { ++ ALOGE("failed to decode video frame."); ++ ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ // H263 doesn't have VOL header, the frame size information is in short header, i.e. the ++ // decoder may detect size change after PVDecodeVideoFrame. ++ if (handlePortSettingsChange()) { ++ return; ++ } ++ ++ if (mPvToOmxTimeMap.indexOfKey(timestamp) >= 0) { ++ // decoder deals in ms, OMX in us. ++ outHeader->nTimeStamp = mPvToOmxTimeMap.valueFor(timestamp); ++ mPvToOmxTimeMap.removeItem(timestamp); ++ } ++ ++ inHeader->nOffset += bufferSize; ++ inHeader->nFilledLen = 0; ++ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ } else { ++ outHeader->nFlags = 0; ++ } ++ ++ if (inHeader->nFilledLen == 0) { ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ } ++ ++ ++mInputBufferCount; ++ ++ outHeader->nOffset = 0; ++ outHeader->nFilledLen = frameSize; ++ ++ List::iterator it = outQueue.begin(); ++ while (it != outQueue.end() && (*it)->mHeader != outHeader) { ++ ++it; ++ } ++ if (it == outQueue.end()) { ++ return; ++ } ++ ++ BufferInfo *outInfo = *it; ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(it); ++ outInfo = NULL; ++ ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ ++ ++mNumSamplesOutput; ++ } ++} ++ ++bool SoftMPEG4::handlePortSettingsChange() { ++ uint32_t disp_width, disp_height; ++ PVGetVideoDimensions(mHandle, (int32 *)&disp_width, (int32 *)&disp_height); ++ ++ uint32_t buf_width, buf_height; ++ PVGetBufferDimensions(mHandle, (int32 *)&buf_width, (int32 *)&buf_height); ++ ++ CHECK_LE(disp_width, buf_width); ++ CHECK_LE(disp_height, buf_height); ++ ++ ALOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d", ++ disp_width, disp_height, buf_width, buf_height); ++ ++ CropSettingsMode cropSettingsMode = kCropUnSet; ++ if (disp_width != buf_width || disp_height != buf_height) { ++ cropSettingsMode = kCropSet; ++ ++ if (mCropWidth != disp_width || mCropHeight != disp_height) { ++ mCropLeft = 0; ++ mCropTop = 0; ++ mCropWidth = disp_width; ++ mCropHeight = disp_height; ++ cropSettingsMode = kCropChanged; ++ } ++ } ++ ++ bool portWillReset = false; ++ const bool fakeStride = true; ++ SoftVideoDecoderOMXComponent::handlePortSettingsChange( ++ &portWillReset, buf_width, buf_height, ++ OMX_COLOR_FormatYUV420Planar, cropSettingsMode, fakeStride); ++ if (portWillReset) { ++ if (mMode == MODE_H263) { ++ PVCleanUpVideoDecoder(mHandle); ++ ++ uint8_t *vol_data[1]; ++ int32_t vol_size = 0; ++ ++ vol_data[0] = NULL; ++ if (!PVInitVideoDecoder( ++ mHandle, vol_data, &vol_size, 1, outputBufferWidth(), outputBufferHeight(), ++ H263_MODE)) { ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ return true; ++ } ++ } ++ ++ mFramesConfigured = false; ++ } ++ ++ return portWillReset; ++} ++ ++void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) { ++ if (portIndex == 0 && mInitialized) { ++ CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE); ++ } ++ mFramesConfigured = false; ++} ++ ++void SoftMPEG4::onReset() { ++ SoftVideoDecoderOMXComponent::onReset(); ++ mPvToOmxTimeMap.clear(); ++ mSignalledError = false; ++ mFramesConfigured = false; ++ if (mInitialized) { ++ PVCleanUpVideoDecoder(mHandle); ++ mInitialized = false; ++ } ++} ++ ++void SoftMPEG4::updatePortDefinitions(bool updateCrop, bool updateInputSize) { ++ SoftVideoDecoderOMXComponent::updatePortDefinitions(updateCrop, updateInputSize); ++ ++ /* We have to align our width and height - this should affect stride! */ ++ OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef; ++ def->format.video.nStride = align(def->format.video.nStride, 16); ++ def->format.video.nSliceHeight = align(def->format.video.nSliceHeight, 16); ++ def->nBufferSize = (def->format.video.nStride * def->format.video.nSliceHeight * 3) / 2; ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ using namespace android; ++ if (!strcmp(name, "OMX.google.h263.decoder")) { ++ return new android::SoftMPEG4( ++ name, "video_decoder.h263", OMX_VIDEO_CodingH263, ++ kH263ProfileLevels, ARRAY_SIZE(kH263ProfileLevels), ++ callbacks, appData, component); ++ } else if (!strcmp(name, "OMX.google.mpeg4.decoder")) { ++ return new android::SoftMPEG4( ++ name, "video_decoder.mpeg4", OMX_VIDEO_CodingMPEG4, ++ kM4VProfileLevels, ARRAY_SIZE(kM4VProfileLevels), ++ callbacks, appData, component); ++ } else { ++ CHECK(!"Unknown component"); ++ } ++ return NULL; ++} ++ +diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h +new file mode 100644 +index 0000000..e399ac9 +--- /dev/null ++++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h +@@ -0,0 +1,79 @@ ++/* ++ * Copyright (C) 2011 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 SOFT_MPEG4_H_ ++ ++#define SOFT_MPEG4_H_ ++ ++#include ++ ++struct tagvideoDecControls; ++ ++namespace android { ++ ++struct SoftMPEG4 : public SoftVideoDecoderOMXComponent { ++ SoftMPEG4(const char *name, ++ const char *componentRole, ++ OMX_VIDEO_CODINGTYPE codingType, ++ const CodecProfileLevel *profileLevels, ++ size_t numProfileLevels, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++protected: ++ virtual ~SoftMPEG4(); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ virtual void onPortFlushCompleted(OMX_U32 portIndex); ++ virtual void onReset(); ++ ++private: ++ enum { ++ kNumInputBuffers = 4, ++ kNumOutputBuffers = 2, ++ }; ++ ++ enum { ++ MODE_MPEG4, ++ MODE_H263, ++ } mMode; ++ ++ tagvideoDecControls *mHandle; ++ ++ size_t mInputBufferCount; ++ ++ bool mSignalledError; ++ bool mInitialized; ++ bool mFramesConfigured; ++ ++ int32_t mNumSamplesOutput; ++ int32_t mPvTime; ++ KeyedVector mPvToOmxTimeMap; ++ ++ status_t initDecoder(); ++ ++ virtual void updatePortDefinitions(bool updateCrop = true, bool updateInputSize = false); ++ bool handlePortSettingsChange(); ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftMPEG4); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_MPEG4_H_ ++ ++ +diff --git a/media/libstagefright/codecs/m4v_h263/dec/exports.lds b/media/libstagefright/codecs/m4v_h263/dec/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/m4v_h263/dec/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.bp b/media/libstagefright/codecs/m4v_h263/enc/Android.bp +new file mode 100644 +index 0000000..d10e40d +--- /dev/null ++++ b/media/libstagefright/codecs/m4v_h263/enc/Android.bp +@@ -0,0 +1,30 @@ ++//############################################################################### ++ ++package { ++ // See: http://go/android-license-faq ++ // A large-scale-change added 'default_applicable_licenses' to import ++ // all of the 'license_kinds' from "frameworks_av_media_libstagefright_license" ++ // to get the below license kinds: ++ // SPDX-license-identifier-Apache-2.0 ++ default_applicable_licenses: ["frameworks_av_media_libstagefright_license"], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_mpeg4enc", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: ["SoftMPEG4Encoder.cpp"], ++ ++ cflags: [ ++ "-DBX_RC", ++ ], ++ ++ static_libs: ["libstagefright_m4vh263enc"], ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ ], ++ cfi: true, ++ }, ++} +diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp +new file mode 100644 +index 0000000..bb1cb0b +--- /dev/null ++++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp +@@ -0,0 +1,550 @@ ++/* ++ * Copyright (C) 2012 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 "SoftMPEG4Encoder" ++#include ++#include ++ ++#include "mp4enc_api.h" ++#include "OMX_Video.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "SoftMPEG4Encoder.h" ++ ++#include ++ ++#ifndef INT32_MAX ++#define INT32_MAX 2147483647 ++#endif ++ ++namespace android { ++ ++template ++static void InitOMXParams(T *params) { ++ params->nSize = sizeof(T); ++ params->nVersion.s.nVersionMajor = 1; ++ params->nVersion.s.nVersionMinor = 0; ++ params->nVersion.s.nRevision = 0; ++ params->nVersion.s.nStep = 0; ++} ++ ++static const CodecProfileLevel kMPEG4ProfileLevels[] = { ++ { OMX_VIDEO_MPEG4ProfileCore, OMX_VIDEO_MPEG4Level2 }, ++}; ++ ++static const CodecProfileLevel kH263ProfileLevels[] = { ++ { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level45 }, ++}; ++ ++SoftMPEG4Encoder::SoftMPEG4Encoder( ++ const char *name, ++ const char *componentRole, ++ OMX_VIDEO_CODINGTYPE codingType, ++ const char *mime, ++ const CodecProfileLevel *profileLevels, ++ size_t numProfileLevels, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SoftVideoEncoderOMXComponent( ++ name, componentRole, codingType, ++ profileLevels, numProfileLevels, ++ 176 /* width */, 144 /* height */, ++ callbacks, appData, component), ++ mEncodeMode(COMBINE_MODE_WITH_ERR_RES), ++ mKeyFrameInterval(30), ++ mNumInputFrames(-1), ++ mStarted(false), ++ mSawInputEOS(false), ++ mSignalledError(false), ++ mHandle(new tagvideoEncControls), ++ mEncParams(new tagvideoEncOptions), ++ mInputFrameData(NULL) { ++ ++ if (codingType == OMX_VIDEO_CodingH263) { ++ mEncodeMode = H263_MODE; ++ } ++ ++ // 256 * 1024 is a magic number for PV's encoder, not sure why ++ const size_t kOutputBufferSize = 256 * 1024; ++ ++ initPorts(kNumBuffers, kNumBuffers, kOutputBufferSize, mime); ++ ++ ALOGI("Construct SoftMPEG4Encoder"); ++} ++ ++SoftMPEG4Encoder::~SoftMPEG4Encoder() { ++ ALOGV("Destruct SoftMPEG4Encoder"); ++ onReset(); ++ releaseEncoder(); ++ List &outQueue = getPortQueue(1); ++ List &inQueue = getPortQueue(0); ++ CHECK(outQueue.empty()); ++ CHECK(inQueue.empty()); ++} ++ ++OMX_ERRORTYPE SoftMPEG4Encoder::initEncParams() { ++ CHECK(mHandle != NULL); ++ memset(mHandle, 0, sizeof(tagvideoEncControls)); ++ ++ CHECK(mEncParams != NULL); ++ memset(mEncParams, 0, sizeof(tagvideoEncOptions)); ++ if (!PVGetDefaultEncOption(mEncParams, 0)) { ++ ALOGE("Failed to get default encoding parameters"); ++ return OMX_ErrorUndefined; ++ } ++ if (mFramerate == 0) { ++ ALOGE("Framerate should not be 0"); ++ return OMX_ErrorUndefined; ++ } ++ mEncParams->encMode = mEncodeMode; ++ mEncParams->encWidth[0] = mWidth; ++ mEncParams->encHeight[0] = mHeight; ++ mEncParams->encFrameRate[0] = mFramerate >> 16; // mFramerate is in Q16 format ++ mEncParams->rcType = VBR_1; ++ mEncParams->vbvDelay = 5.0f; ++ ++ // FIXME: ++ // Add more profile and level support for MPEG4 encoder ++ mEncParams->profile_level = CORE_PROFILE_LEVEL2; ++ mEncParams->packetSize = 32; ++ mEncParams->rvlcEnable = PV_OFF; ++ mEncParams->numLayers = 1; ++ mEncParams->timeIncRes = 1000; ++ mEncParams->tickPerSrc = ((int64_t)mEncParams->timeIncRes << 16) / mFramerate; ++ ++ mEncParams->bitRate[0] = mBitrate; ++ mEncParams->iQuant[0] = 15; ++ mEncParams->pQuant[0] = 12; ++ mEncParams->quantType[0] = 0; ++ mEncParams->noFrameSkipped = PV_OFF; ++ ++ if (mColorFormat != OMX_COLOR_FormatYUV420Planar || mInputDataIsMeta) { ++ // Color conversion is needed. ++ free(mInputFrameData); ++ mInputFrameData = NULL; ++ if (((uint64_t)mWidth * mHeight) > ((uint64_t)INT32_MAX / 3)) { ++ ALOGE("b/25812794, Buffer size is too big."); ++ return OMX_ErrorBadParameter; ++ } ++ mInputFrameData = ++ (uint8_t *) malloc((mWidth * mHeight * 3 ) >> 1); ++ CHECK(mInputFrameData != NULL); ++ } ++ ++ // PV's MPEG4 encoder requires the video dimension of multiple ++ if (mWidth % 16 != 0 || mHeight % 16 != 0) { ++ ALOGE("Video frame size %dx%d must be a multiple of 16", ++ mWidth, mHeight); ++ return OMX_ErrorBadParameter; ++ } ++ ++ // Set IDR frame refresh interval ++ mEncParams->intraPeriod = mKeyFrameInterval; ++ ++ mEncParams->numIntraMB = 0; ++ mEncParams->sceneDetect = PV_ON; ++ mEncParams->searchRange = 16; ++ mEncParams->mv8x8Enable = PV_OFF; ++ mEncParams->gobHeaderInterval = 0; ++ mEncParams->useACPred = PV_ON; ++ mEncParams->intraDCVlcTh = 0; ++ ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftMPEG4Encoder::initEncoder() { ++ CHECK(!mStarted); ++ ++ OMX_ERRORTYPE errType = OMX_ErrorNone; ++ if (OMX_ErrorNone != (errType = initEncParams())) { ++ ALOGE("Failed to initialized encoder params"); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); ++ return errType; ++ } ++ ++ if (!PVInitVideoEncoder(mHandle, mEncParams)) { ++ ALOGE("Failed to initialize the encoder"); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); ++ return OMX_ErrorUndefined; ++ } ++ ++ mNumInputFrames = -1; // 1st buffer for codec specific data ++ mStarted = true; ++ ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftMPEG4Encoder::releaseEncoder() { ++ if (mEncParams) { ++ delete mEncParams; ++ mEncParams = NULL; ++ } ++ ++ if (mHandle) { ++ delete mHandle; ++ mHandle = NULL; ++ } ++ ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftMPEG4Encoder::internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamVideoBitrate: ++ { ++ OMX_VIDEO_PARAM_BITRATETYPE *bitRate = ++ (OMX_VIDEO_PARAM_BITRATETYPE *) params; ++ ++ if (!isValidOMXParam(bitRate)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (bitRate->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ bitRate->eControlRate = OMX_Video_ControlRateVariable; ++ bitRate->nTargetBitrate = mBitrate; ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamVideoH263: ++ { ++ OMX_VIDEO_PARAM_H263TYPE *h263type = ++ (OMX_VIDEO_PARAM_H263TYPE *)params; ++ ++ if (!isValidOMXParam(h263type)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (h263type->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ h263type->nAllowedPictureTypes = ++ (OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP); ++ h263type->eProfile = OMX_VIDEO_H263ProfileBaseline; ++ h263type->eLevel = OMX_VIDEO_H263Level45; ++ h263type->bPLUSPTYPEAllowed = OMX_FALSE; ++ h263type->bForceRoundingTypeToZero = OMX_FALSE; ++ h263type->nPictureHeaderRepetition = 0; ++ h263type->nGOBHeaderInterval = 0; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamVideoMpeg4: ++ { ++ OMX_VIDEO_PARAM_MPEG4TYPE *mpeg4type = ++ (OMX_VIDEO_PARAM_MPEG4TYPE *)params; ++ ++ if (!isValidOMXParam(mpeg4type)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (mpeg4type->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ mpeg4type->eProfile = OMX_VIDEO_MPEG4ProfileCore; ++ mpeg4type->eLevel = OMX_VIDEO_MPEG4Level2; ++ mpeg4type->nAllowedPictureTypes = ++ (OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP); ++ mpeg4type->nBFrames = 0; ++ mpeg4type->nIDCVLCThreshold = 0; ++ mpeg4type->bACPred = OMX_TRUE; ++ mpeg4type->nMaxPacketSize = 256; ++ mpeg4type->nTimeIncRes = 1000; ++ mpeg4type->nHeaderExtension = 0; ++ mpeg4type->bReversibleVLC = OMX_FALSE; ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SoftVideoEncoderOMXComponent::internalGetParameter(index, params); ++ } ++} ++ ++OMX_ERRORTYPE SoftMPEG4Encoder::internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params) { ++ int32_t indexFull = index; ++ ++ switch (indexFull) { ++ case OMX_IndexParamVideoBitrate: ++ { ++ OMX_VIDEO_PARAM_BITRATETYPE *bitRate = ++ (OMX_VIDEO_PARAM_BITRATETYPE *) params; ++ ++ if (!isValidOMXParam(bitRate)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (bitRate->nPortIndex != 1 || ++ bitRate->eControlRate != OMX_Video_ControlRateVariable) { ++ return OMX_ErrorUndefined; ++ } ++ ++ mBitrate = bitRate->nTargetBitrate; ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamVideoH263: ++ { ++ OMX_VIDEO_PARAM_H263TYPE *h263type = ++ (OMX_VIDEO_PARAM_H263TYPE *)params; ++ ++ if (!isValidOMXParam(h263type)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (h263type->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (h263type->eProfile != OMX_VIDEO_H263ProfileBaseline || ++ h263type->eLevel != OMX_VIDEO_H263Level45 || ++ (h263type->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) || ++ h263type->bPLUSPTYPEAllowed != OMX_FALSE || ++ h263type->bForceRoundingTypeToZero != OMX_FALSE || ++ h263type->nPictureHeaderRepetition != 0 || ++ h263type->nGOBHeaderInterval != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamVideoMpeg4: ++ { ++ OMX_VIDEO_PARAM_MPEG4TYPE *mpeg4type = ++ (OMX_VIDEO_PARAM_MPEG4TYPE *)params; ++ ++ if (!isValidOMXParam(mpeg4type)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (mpeg4type->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (mpeg4type->eProfile != OMX_VIDEO_MPEG4ProfileCore || ++ mpeg4type->eLevel > OMX_VIDEO_MPEG4Level2 || ++ (mpeg4type->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) || ++ mpeg4type->nBFrames != 0 || ++ mpeg4type->nIDCVLCThreshold != 0 || ++ mpeg4type->bACPred != OMX_TRUE || ++ mpeg4type->nMaxPacketSize != 256 || ++ mpeg4type->nTimeIncRes != 1000 || ++ mpeg4type->nHeaderExtension != 0 || ++ mpeg4type->bReversibleVLC != OMX_FALSE) { ++ return OMX_ErrorUndefined; ++ } ++ ++ mKeyFrameInterval = int32_t(mpeg4type->nPFrames + 1); ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SoftVideoEncoderOMXComponent::internalSetParameter(index, params); ++ } ++} ++ ++void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) { ++ if (mSignalledError || mSawInputEOS) { ++ return; ++ } ++ ++ if (!mStarted) { ++ if (OMX_ErrorNone != initEncoder()) { ++ return; ++ } ++ } ++ ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ ++ while (!mSawInputEOS && !inQueue.empty() && !outQueue.empty()) { ++ BufferInfo *inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ ++ outHeader->nTimeStamp = 0; ++ outHeader->nFlags = 0; ++ outHeader->nOffset = 0; ++ outHeader->nFilledLen = 0; ++ outHeader->nOffset = 0; ++ ++ uint8_t *outPtr = (uint8_t *) outHeader->pBuffer; ++ int32_t dataLength = outHeader->nAllocLen; ++ ++ if (mNumInputFrames < 0) { ++ if (!PVGetVolHeader(mHandle, outPtr, &dataLength, 0)) { ++ ALOGE("Failed to get VOL header"); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); ++ return; ++ } ++ ALOGV("Output VOL header: %d bytes", dataLength); ++ ++mNumInputFrames; ++ outHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG; ++ outHeader->nFilledLen = dataLength; ++ outQueue.erase(outQueue.begin()); ++ outInfo->mOwnedByUs = false; ++ notifyFillBufferDone(outHeader); ++ return; ++ } ++ ++ // Save the input buffer info so that it can be ++ // passed to an output buffer ++ InputBufferInfo info; ++ info.mTimeUs = inHeader->nTimeStamp; ++ info.mFlags = inHeader->nFlags; ++ mInputBufferInfoVec.push(info); ++ ++ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ mSawInputEOS = true; ++ } ++ ++ if (inHeader->nFilledLen > 0) { ++ OMX_ERRORTYPE error = validateInputBuffer(inHeader); ++ if (error != OMX_ErrorNone) { ++ ALOGE("b/69065651"); ++ android_errorWriteLog(0x534e4554, "69065651"); ++ mSignalledError = true; ++ notify(OMX_EventError, error, 0, 0); ++ return; ++ } ++ const uint8_t *inputData = NULL; ++ if (mInputDataIsMeta) { ++ inputData = ++ extractGraphicBuffer( ++ mInputFrameData, (mWidth * mHeight * 3) >> 1, ++ inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen, ++ mWidth, mHeight); ++ if (inputData == NULL) { ++ ALOGE("Unable to extract gralloc buffer in metadata mode"); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); ++ return; ++ } ++ } else { ++ inputData = (const uint8_t *)inHeader->pBuffer + inHeader->nOffset; ++ if (mColorFormat != OMX_COLOR_FormatYUV420Planar) { ++ ConvertYUV420SemiPlanarToYUV420Planar( ++ inputData, mInputFrameData, mWidth, mHeight); ++ inputData = mInputFrameData; ++ } ++ } ++ ++ CHECK(inputData != NULL); ++ ++ VideoEncFrameIO vin, vout; ++ memset(&vin, 0, sizeof(vin)); ++ memset(&vout, 0, sizeof(vout)); ++ vin.height = align(mHeight, 16); ++ vin.pitch = align(mWidth, 16); ++ vin.timestamp = (inHeader->nTimeStamp + 500) / 1000; // in ms ++ vin.yChan = (uint8_t *)inputData; ++ vin.uChan = vin.yChan + vin.height * vin.pitch; ++ vin.vChan = vin.uChan + ((vin.height * vin.pitch) >> 2); ++ ++ ULong modTimeMs = 0; ++ int32_t nLayer = 0; ++ MP4HintTrack hintTrack; ++ if (!PVEncodeVideoFrame(mHandle, &vin, &vout, ++ &modTimeMs, outPtr, &dataLength, &nLayer) || ++ !PVGetHintTrack(mHandle, &hintTrack)) { ++ ALOGE("Failed to encode frame or get hink track at frame %" PRId64, ++ mNumInputFrames); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); ++ } ++ CHECK(NULL == PVGetOverrunBuffer(mHandle)); ++ if (hintTrack.CodeType == 0) { // I-frame serves as sync frame ++ outHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME; ++ } ++ ++ ++mNumInputFrames; ++ } else { ++ dataLength = 0; ++ } ++ ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ ++ outQueue.erase(outQueue.begin()); ++ CHECK(!mInputBufferInfoVec.empty()); ++ InputBufferInfo *inputBufInfo = mInputBufferInfoVec.begin(); ++ outHeader->nTimeStamp = inputBufInfo->mTimeUs; ++ outHeader->nFlags |= (inputBufInfo->mFlags | OMX_BUFFERFLAG_ENDOFFRAME); ++ outHeader->nFilledLen = dataLength; ++ mInputBufferInfoVec.erase(mInputBufferInfoVec.begin()); ++ outInfo->mOwnedByUs = false; ++ notifyFillBufferDone(outHeader); ++ } ++} ++ ++void SoftMPEG4Encoder::onReset() { ++ if (!mStarted) { ++ return; ++ } ++ ++ PVCleanUpVideoEncoder(mHandle); ++ ++ free(mInputFrameData); ++ mInputFrameData = NULL; ++ ++ mStarted = false; ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ using namespace android; ++ if (!strcmp(name, "OMX.google.h263.encoder")) { ++ return new android::SoftMPEG4Encoder( ++ name, "video_encoder.h263", OMX_VIDEO_CodingH263, MEDIA_MIMETYPE_VIDEO_H263, ++ kH263ProfileLevels, NELEM(kH263ProfileLevels), ++ callbacks, appData, component); ++ } else if (!strcmp(name, "OMX.google.mpeg4.encoder")) { ++ return new android::SoftMPEG4Encoder( ++ name, "video_encoder.mpeg4", OMX_VIDEO_CodingMPEG4, MEDIA_MIMETYPE_VIDEO_MPEG4, ++ kMPEG4ProfileLevels, NELEM(kMPEG4ProfileLevels), ++ callbacks, appData, component); ++ } else { ++ CHECK(!"Unknown component"); ++ } ++ return NULL; ++} +diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h +new file mode 100644 +index 0000000..71e1170 +--- /dev/null ++++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h +@@ -0,0 +1,88 @@ ++/* ++ * Copyright (C) 2012 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 SOFT_MPEG4_ENCODER_H_ ++#define SOFT_MPEG4_ENCODER_H_ ++ ++#include ++#include ++#include "mp4enc_api.h" ++ ++ ++namespace android { ++ ++struct CodecProfileLevel; ++ ++struct SoftMPEG4Encoder : public SoftVideoEncoderOMXComponent { ++ SoftMPEG4Encoder( ++ const char *name, ++ const char *componentRole, ++ OMX_VIDEO_CODINGTYPE codingType, ++ const char *mime, ++ const CodecProfileLevel *profileLevels, ++ size_t numProfileLevels, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++ // Override SimpleSoftOMXComponent methods ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params); ++ ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ ++ virtual void onReset(); ++ ++protected: ++ virtual ~SoftMPEG4Encoder(); ++ ++private: ++ enum { ++ kNumBuffers = 2, ++ }; ++ ++ // OMX input buffer's timestamp and flags ++ typedef struct { ++ int64_t mTimeUs; ++ int32_t mFlags; ++ } InputBufferInfo; ++ ++ MP4EncodingMode mEncodeMode; ++ int32_t mKeyFrameInterval; // 1: all I-frames, <0: infinite ++ ++ int64_t mNumInputFrames; ++ bool mStarted; ++ bool mSawInputEOS; ++ bool mSignalledError; ++ ++ tagvideoEncControls *mHandle; ++ tagvideoEncOptions *mEncParams; ++ uint8_t *mInputFrameData; ++ Vector mInputBufferInfoVec; ++ ++ OMX_ERRORTYPE initEncParams(); ++ OMX_ERRORTYPE initEncoder(); ++ OMX_ERRORTYPE releaseEncoder(); ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftMPEG4Encoder); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_MPEG4_ENCODER_H_ +diff --git a/media/libstagefright/codecs/m4v_h263/enc/exports.lds b/media/libstagefright/codecs/m4v_h263/enc/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/m4v_h263/enc/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/mp3dec/Android.bp b/media/libstagefright/codecs/mp3dec/Android.bp +new file mode 100644 +index 0000000..b669c84 +--- /dev/null ++++ b/media/libstagefright/codecs/mp3dec/Android.bp +@@ -0,0 +1,27 @@ ++ ++package { ++ // See: http://go/android-license-faq ++ // A large-scale-change added 'default_applicable_licenses' to import ++ // all of the 'license_kinds' from "frameworks_av_media_libstagefright_license" ++ // to get the below license kinds: ++ // SPDX-license-identifier-Apache-2.0 ++ default_applicable_licenses: ["frameworks_av_media_libstagefright_license"], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_mp3dec", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: ["SoftMP3.cpp"], ++ ++ version_script: "exports.lds", ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ ], ++ cfi: true, ++ }, ++ ++ static_libs: ["libstagefright_mp3dec"], ++} +diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp +new file mode 100644 +index 0000000..07bb45a +--- /dev/null ++++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp +@@ -0,0 +1,506 @@ ++/* ++ * Copyright (C) 2011 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 "SoftMP3" ++#include ++ ++#include "SoftMP3.h" ++ ++#include ++#include ++ ++#include ++ ++namespace android { ++ ++template ++static void InitOMXParams(T *params) { ++ params->nSize = sizeof(T); ++ params->nVersion.s.nVersionMajor = 1; ++ params->nVersion.s.nVersionMinor = 0; ++ params->nVersion.s.nRevision = 0; ++ params->nVersion.s.nStep = 0; ++} ++ ++SoftMP3::SoftMP3( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SimpleSoftOMXComponent(name, callbacks, appData, component), ++ mConfig(new tPVMP3DecoderExternal), ++ mDecoderBuf(NULL), ++ mAnchorTimeUs(0), ++ mNumFramesOutput(0), ++ mNumChannels(2), ++ mSamplingRate(44100), ++ mSignalledError(false), ++ mSawInputEos(false), ++ mSignalledOutputEos(false), ++ mOutputPortSettingsChange(NONE) { ++ initPorts(); ++ initDecoder(); ++} ++ ++SoftMP3::~SoftMP3() { ++ if (mDecoderBuf != NULL) { ++ free(mDecoderBuf); ++ mDecoderBuf = NULL; ++ } ++ ++ delete mConfig; ++ mConfig = NULL; ++} ++ ++void SoftMP3::initPorts() { ++ OMX_PARAM_PORTDEFINITIONTYPE def; ++ InitOMXParams(&def); ++ ++ def.nPortIndex = 0; ++ def.eDir = OMX_DirInput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = 8192; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 1; ++ ++ def.format.audio.cMIMEType = ++ const_cast(MEDIA_MIMETYPE_AUDIO_MPEG); ++ ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingMP3; ++ ++ addPort(def); ++ ++ def.nPortIndex = 1; ++ def.eDir = OMX_DirOutput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = kOutputBufferSize; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 2; ++ ++ def.format.audio.cMIMEType = const_cast("audio/raw"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; ++ ++ addPort(def); ++} ++ ++void SoftMP3::initDecoder() { ++ mConfig->equalizerType = flat; ++ mConfig->crcEnabled = false; ++ ++ uint32_t memRequirements = pvmp3_decoderMemRequirements(); ++ mDecoderBuf = calloc(1, memRequirements); ++ ++ pvmp3_InitDecoder(mConfig, mDecoderBuf); ++ mIsFirst = true; ++} ++ ++void *SoftMP3::memsetSafe(OMX_BUFFERHEADERTYPE *outHeader, int c, size_t len) { ++ if (len > outHeader->nAllocLen) { ++ ALOGE("memset buffer too small: got %u, expected %zu", outHeader->nAllocLen, len); ++ android_errorWriteLog(0x534e4554, "29422022"); ++ notify(OMX_EventError, OMX_ErrorUndefined, OUTPUT_BUFFER_TOO_SMALL, NULL); ++ mSignalledError = true; ++ return NULL; ++ } ++ return memset(outHeader->pBuffer, c, len); ++} ++ ++OMX_ERRORTYPE SoftMP3::internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamAudioPortFormat: ++ { ++ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (formatParams->nIndex > 0) { ++ return OMX_ErrorNoMore; ++ } ++ ++ formatParams->eEncoding = ++ (formatParams->nPortIndex == 0) ++ ? OMX_AUDIO_CodingMP3 : OMX_AUDIO_CodingPCM; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ pcmParams->eNumData = OMX_NumericalDataSigned; ++ pcmParams->eEndian = OMX_EndianBig; ++ pcmParams->bInterleaved = OMX_TRUE; ++ pcmParams->nBitPerSample = 16; ++ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; ++ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; ++ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; ++ ++ pcmParams->nChannels = mNumChannels; ++ pcmParams->nSamplingRate = mSamplingRate; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioMp3: ++ { ++ OMX_AUDIO_PARAM_MP3TYPE *mp3Params = ++ (OMX_AUDIO_PARAM_MP3TYPE *)params; ++ ++ if (!isValidOMXParam(mp3Params)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (mp3Params->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ mp3Params->nChannels = mNumChannels; ++ mp3Params->nBitRate = 0 /* unknown */; ++ mp3Params->nSampleRate = mSamplingRate; ++ // other fields are encoder-only ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalGetParameter(index, params); ++ } ++} ++ ++OMX_ERRORTYPE SoftMP3::internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamStandardComponentRole: ++ { ++ const OMX_PARAM_COMPONENTROLETYPE *roleParams = ++ (const OMX_PARAM_COMPONENTROLETYPE *)params; ++ ++ if (!isValidOMXParam(roleParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (strncmp((const char *)roleParams->cRole, ++ "audio_decoder.mp3", ++ OMX_MAX_STRINGNAME_SIZE - 1)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPortFormat: ++ { ++ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if ((formatParams->nPortIndex == 0 ++ && formatParams->eEncoding != OMX_AUDIO_CodingMP3) ++ || (formatParams->nPortIndex == 1 ++ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (const OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ mNumChannels = pcmParams->nChannels; ++ mSamplingRate = pcmParams->nSamplingRate; ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalSetParameter(index, params); ++ } ++} ++ ++void SoftMP3::onQueueFilled(OMX_U32 /* portIndex */) { ++ if (mSignalledError || mOutputPortSettingsChange != NONE) { ++ return; ++ } ++ ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ ++ while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) { ++ BufferInfo *inInfo = NULL; ++ OMX_BUFFERHEADERTYPE *inHeader = NULL; ++ if (!inQueue.empty()) { ++ inInfo = *inQueue.begin(); ++ inHeader = inInfo->mHeader; ++ } ++ ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ outHeader->nFlags = 0; ++ ++ if (inHeader) { ++ if (inHeader->nOffset == 0 && inHeader->nFilledLen) { ++ mAnchorTimeUs = inHeader->nTimeStamp; ++ mNumFramesOutput = 0; ++ } ++ ++ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ mSawInputEos = true; ++ if (mIsFirst && !inHeader->nFilledLen) { ++ ALOGV("empty first EOS"); ++ outHeader->nFilledLen = 0; ++ outHeader->nTimeStamp = inHeader->nTimeStamp; ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ mSignalledOutputEos = true; ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ notifyFillBufferDone(outHeader); ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ notifyEmptyBufferDone(inHeader); ++ return; ++ } ++ } ++ ++ mConfig->pInputBuffer = ++ inHeader->pBuffer + inHeader->nOffset; ++ ++ mConfig->inputBufferCurrentLength = inHeader->nFilledLen; ++ } else { ++ mConfig->pInputBuffer = NULL; ++ mConfig->inputBufferCurrentLength = 0; ++ } ++ mConfig->inputBufferMaxLength = 0; ++ mConfig->inputBufferUsedLength = 0; ++ ++ mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t); ++ if ((int32_t)outHeader->nAllocLen < mConfig->outputFrameSize) { ++ ALOGE("input buffer too small: got %u, expected %u", ++ outHeader->nAllocLen, mConfig->outputFrameSize); ++ android_errorWriteLog(0x534e4554, "27793371"); ++ notify(OMX_EventError, OMX_ErrorUndefined, OUTPUT_BUFFER_TOO_SMALL, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ mConfig->pOutputBuffer = ++ reinterpret_cast(outHeader->pBuffer); ++ ++ ERROR_CODE decoderErr; ++ if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf)) ++ != NO_DECODING_ERROR) { ++ ALOGV("mp3 decoder returned error %d", decoderErr); ++ ++ if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR ++ && decoderErr != SIDE_INFO_ERROR) { ++ ALOGE("mp3 decoder returned error %d", decoderErr); ++ ++ notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ if (mConfig->outputFrameSize == 0) { ++ mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t); ++ } ++ ++ if (decoderErr == NO_ENOUGH_MAIN_DATA_ERROR && mSawInputEos) { ++ if (!mIsFirst) { ++ // pad the end of the stream with 529 samples, since that many samples ++ // were trimmed off the beginning when decoding started ++ outHeader->nOffset = 0; ++ outHeader->nFilledLen = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t); ++ ++ if (!memsetSafe(outHeader, 0, outHeader->nFilledLen)) { ++ return; ++ } ++ ++ } ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ mSignalledOutputEos = true; ++ } else { ++ // This is recoverable, just ignore the current frame and ++ // play silence instead. ++ ++ // TODO: should we skip silence (and consume input data) ++ // if mIsFirst is true as we may not have a valid ++ // mConfig->samplingRate and mConfig->num_channels? ++ ALOGV_IF(mIsFirst, "insufficient data for first frame, sending silence"); ++ if (!memsetSafe(outHeader, 0, mConfig->outputFrameSize * sizeof(int16_t))) { ++ return; ++ } ++ ++ if (inHeader) { ++ mConfig->inputBufferUsedLength = inHeader->nFilledLen; ++ } ++ } ++ } else if (mConfig->samplingRate != mSamplingRate ++ || mConfig->num_channels != mNumChannels) { ++ mSamplingRate = mConfig->samplingRate; ++ mNumChannels = mConfig->num_channels; ++ ++ notify(OMX_EventPortSettingsChanged, 1, 0, NULL); ++ mOutputPortSettingsChange = AWAITING_DISABLED; ++ return; ++ } ++ ++ if (mIsFirst) { ++ mIsFirst = false; ++ // The decoder delay is 529 samples, so trim that many samples off ++ // the start of the first output buffer. This essentially makes this ++ // decoder have zero delay, which the rest of the pipeline assumes. ++ outHeader->nOffset = ++ kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t); ++ ++ outHeader->nFilledLen = ++ mConfig->outputFrameSize * sizeof(int16_t) - outHeader->nOffset; ++ } else if (!mSignalledOutputEos) { ++ outHeader->nOffset = 0; ++ outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t); ++ } ++ ++ outHeader->nTimeStamp = ++ mAnchorTimeUs + (mNumFramesOutput * 1000000LL) / mSamplingRate; ++ ++ if (inHeader) { ++ CHECK_GE((int32_t)inHeader->nFilledLen, mConfig->inputBufferUsedLength); ++ ++ inHeader->nOffset += mConfig->inputBufferUsedLength; ++ inHeader->nFilledLen -= mConfig->inputBufferUsedLength; ++ ++ ++ if (inHeader->nFilledLen == 0) { ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ } ++ } ++ ++ mNumFramesOutput += mConfig->outputFrameSize / mNumChannels; ++ ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ outInfo = NULL; ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ } ++} ++ ++void SoftMP3::onPortFlushCompleted(OMX_U32 portIndex) { ++ if (portIndex == 0) { ++ // Make sure that the next buffer output does not still ++ // depend on fragments from the last one decoded. ++ pvmp3_InitDecoder(mConfig, mDecoderBuf); ++ mIsFirst = true; ++ mSignalledError = false; ++ mSawInputEos = false; ++ mSignalledOutputEos = false; ++ } ++} ++ ++void SoftMP3::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { ++ if (portIndex != 1) { ++ return; ++ } ++ ++ switch (mOutputPortSettingsChange) { ++ case NONE: ++ break; ++ ++ case AWAITING_DISABLED: ++ { ++ CHECK(!enabled); ++ mOutputPortSettingsChange = AWAITING_ENABLED; ++ break; ++ } ++ ++ default: ++ { ++ CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); ++ CHECK(enabled); ++ mOutputPortSettingsChange = NONE; ++ break; ++ } ++ } ++} ++ ++void SoftMP3::onReset() { ++ pvmp3_InitDecoder(mConfig, mDecoderBuf); ++ mIsFirst = true; ++ mSignalledError = false; ++ mSawInputEos = false; ++ mSignalledOutputEos = false; ++ mOutputPortSettingsChange = NONE; ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ return new android::SoftMP3(name, callbacks, appData, component); ++} +diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.h b/media/libstagefright/codecs/mp3dec/SoftMP3.h +new file mode 100644 +index 0000000..976fd00 +--- /dev/null ++++ b/media/libstagefright/codecs/mp3dec/SoftMP3.h +@@ -0,0 +1,84 @@ ++/* ++ * Copyright (C) 2011 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 SOFT_MP3_H_ ++ ++#define SOFT_MP3_H_ ++ ++#include ++ ++struct tPVMP3DecoderExternal; ++ ++namespace android { ++ ++struct SoftMP3 : public SimpleSoftOMXComponent { ++ SoftMP3(const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++protected: ++ virtual ~SoftMP3(); ++ ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params); ++ ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ virtual void onPortFlushCompleted(OMX_U32 portIndex); ++ virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled); ++ virtual void onReset(); ++ ++private: ++ enum { ++ kNumBuffers = 4, ++ kOutputBufferSize = 4608 * 2, ++ kPVMP3DecoderDelay = 529 // frames ++ }; ++ ++ tPVMP3DecoderExternal *mConfig; ++ void *mDecoderBuf; ++ int64_t mAnchorTimeUs; ++ int64_t mNumFramesOutput; ++ ++ int32_t mNumChannels; ++ int32_t mSamplingRate; ++ ++ bool mIsFirst; ++ bool mSignalledError; ++ bool mSawInputEos; ++ bool mSignalledOutputEos; ++ ++ enum { ++ NONE, ++ AWAITING_DISABLED, ++ AWAITING_ENABLED ++ } mOutputPortSettingsChange; ++ ++ void initPorts(); ++ void initDecoder(); ++ void *memsetSafe(OMX_BUFFERHEADERTYPE *outHeader, int c, size_t len); ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftMP3); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_MP3_H_ ++ ++ +diff --git a/media/libstagefright/codecs/mp3dec/exports.lds b/media/libstagefright/codecs/mp3dec/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/mp3dec/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/mpeg2dec/Android.bp b/media/libstagefright/codecs/mpeg2dec/Android.bp +new file mode 100644 +index 0000000..abd1379 +--- /dev/null ++++ b/media/libstagefright/codecs/mpeg2dec/Android.bp +@@ -0,0 +1,32 @@ ++package { ++ // See: http://go/android-license-faq ++ // A large-scale-change added 'default_applicable_licenses' to import ++ // all of the 'license_kinds' from "frameworks_av_media_libstagefright_license" ++ // to get the below license kinds: ++ // SPDX-license-identifier-Apache-2.0 ++ default_applicable_licenses: ["frameworks_av_media_libstagefright_license"], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_mpeg2dec", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ static_libs: ["libmpeg2dec"], ++ srcs: ["SoftMPEG2.cpp"], ++ ++ cflags: [ ++ "-Wall", ++ "-Wno-unused-variable", ++ ], ++ ++ version_script: "exports.lds", ++ ++ ldflags: ["-Wl,-Bsymbolic"], ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ ], ++ cfi: true, ++ }, ++} +diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp +new file mode 100644 +index 0000000..9f8001f +--- /dev/null ++++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp +@@ -0,0 +1,872 @@ ++/* ++ * Copyright 2015 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 "SoftMPEG2" ++#include ++ ++#include "iv_datatypedef.h" ++#include "iv.h" ++#include "ivd.h" ++#include "impeg2d.h" ++#include "SoftMPEG2.h" ++ ++#include ++#include ++#include ++ ++namespace android { ++ ++#define componentName "video_decoder.mpeg2" ++#define codingType OMX_VIDEO_CodingMPEG2 ++#define CODEC_MIME_TYPE MEDIA_MIMETYPE_VIDEO_MPEG2 ++ ++/** Function and structure definitions to keep code similar for each codec */ ++#define ivdec_api_function impeg2d_api_function ++#define ivdext_init_ip_t impeg2d_init_ip_t ++#define ivdext_init_op_t impeg2d_init_op_t ++#define ivdext_fill_mem_rec_ip_t impeg2d_fill_mem_rec_ip_t ++#define ivdext_fill_mem_rec_op_t impeg2d_fill_mem_rec_op_t ++#define ivdext_ctl_set_num_cores_ip_t impeg2d_ctl_set_num_cores_ip_t ++#define ivdext_ctl_set_num_cores_op_t impeg2d_ctl_set_num_cores_op_t ++ ++#define IVDEXT_CMD_CTL_SET_NUM_CORES \ ++ (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_SET_NUM_CORES ++ ++static const CodecProfileLevel kProfileLevels[] = { ++ { OMX_VIDEO_MPEG2ProfileSimple, OMX_VIDEO_MPEG2LevelHL }, ++ ++ { OMX_VIDEO_MPEG2ProfileMain , OMX_VIDEO_MPEG2LevelHL }, ++}; ++ ++SoftMPEG2::SoftMPEG2( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SoftVideoDecoderOMXComponent( ++ name, componentName, codingType, ++ kProfileLevels, ARRAY_SIZE(kProfileLevels), ++ 320 /* width */, 240 /* height */, callbacks, ++ appData, component), ++ mCodecCtx(NULL), ++ mMemRecords(NULL), ++ mFlushOutBuffer(NULL), ++ mOmxColorFormat(OMX_COLOR_FormatYUV420Planar), ++ mIvColorFormat(IV_YUV_420P), ++ mNewWidth(mWidth), ++ mNewHeight(mHeight), ++ mChangingResolution(false), ++ mSignalledError(false), ++ mStride(mWidth) { ++ initPorts(kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, CODEC_MIME_TYPE); ++ ++ // If input dump is enabled, then open create an empty file ++ GENERATE_FILE_NAMES(); ++ CREATE_DUMP_FILE(mInFile); ++} ++ ++SoftMPEG2::~SoftMPEG2() { ++ if (OK != deInitDecoder()) { ++ ALOGE("Failed to deinit decoder"); ++ notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++} ++ ++ ++static ssize_t getMinTimestampIdx(OMX_S64 *pNTimeStamp, bool *pIsTimeStampValid) { ++ OMX_S64 minTimeStamp = LLONG_MAX; ++ ssize_t idx = -1; ++ for (ssize_t i = 0; i < MAX_TIME_STAMPS; i++) { ++ if (pIsTimeStampValid[i]) { ++ if (pNTimeStamp[i] < minTimeStamp) { ++ minTimeStamp = pNTimeStamp[i]; ++ idx = i; ++ } ++ } ++ } ++ return idx; ++} ++ ++static size_t GetCPUCoreCount() { ++ long cpuCoreCount = 1; ++#if defined(_SC_NPROCESSORS_ONLN) ++ cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); ++#else ++ // _SC_NPROC_ONLN must be defined... ++ cpuCoreCount = sysconf(_SC_NPROC_ONLN); ++#endif ++ CHECK(cpuCoreCount >= 1); ++ ALOGV("Number of CPU cores: %ld", cpuCoreCount); ++ return (size_t)cpuCoreCount; ++} ++ ++void SoftMPEG2::logVersion() { ++ ivd_ctl_getversioninfo_ip_t s_ctl_ip; ++ ivd_ctl_getversioninfo_op_t s_ctl_op; ++ UWORD8 au1_buf[512]; ++ IV_API_CALL_STATUS_T status; ++ ++ s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION; ++ s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t); ++ s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t); ++ s_ctl_ip.pv_version_buffer = au1_buf; ++ s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf); ++ ++ status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGE("Error in getting version number: 0x%x", ++ s_ctl_op.u4_error_code); ++ } else { ++ ALOGV("Ittiam decoder version number: %s", ++ (char *)s_ctl_ip.pv_version_buffer); ++ } ++ return; ++} ++ ++status_t SoftMPEG2::setParams(size_t stride) { ++ ivd_ctl_set_config_ip_t s_ctl_ip; ++ ivd_ctl_set_config_op_t s_ctl_op; ++ IV_API_CALL_STATUS_T status; ++ s_ctl_ip.u4_disp_wd = (UWORD32)stride; ++ s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE; ++ ++ s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT; ++ s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME; ++ s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS; ++ s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t); ++ s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t); ++ ++ ALOGV("Set the run-time (dynamic) parameters stride = %zu", stride); ++ status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGE("Error in setting the run-time parameters: 0x%x", ++ s_ctl_op.u4_error_code); ++ ++ return UNKNOWN_ERROR; ++ } ++ return OK; ++} ++ ++status_t SoftMPEG2::resetPlugin() { ++ mIsInFlush = false; ++ mReceivedEOS = false; ++ memset(mTimeStamps, 0, sizeof(mTimeStamps)); ++ memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid)); ++ ++ /* Initialize both start and end times */ ++ gettimeofday(&mTimeStart, NULL); ++ gettimeofday(&mTimeEnd, NULL); ++ ++ return OK; ++} ++ ++status_t SoftMPEG2::resetDecoder() { ++ ivd_ctl_reset_ip_t s_ctl_ip; ++ ivd_ctl_reset_op_t s_ctl_op; ++ IV_API_CALL_STATUS_T status; ++ ++ s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET; ++ s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t); ++ s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t); ++ ++ status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op); ++ if (IV_SUCCESS != status) { ++ ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code); ++ return UNKNOWN_ERROR; ++ } ++ ++ /* Set the run-time (dynamic) parameters */ ++ setParams(outputBufferWidth()); ++ ++ /* Set number of cores/threads to be used by the codec */ ++ setNumCores(); ++ ++ mStride = 0; ++ mSignalledError = false; ++ ++ return OK; ++} ++ ++status_t SoftMPEG2::setNumCores() { ++ ivdext_ctl_set_num_cores_ip_t s_set_cores_ip; ++ ivdext_ctl_set_num_cores_op_t s_set_cores_op; ++ IV_API_CALL_STATUS_T status; ++ s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES; ++ s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES); ++ s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t); ++ s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t); ++ ++ status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip, (void *)&s_set_cores_op); ++ if (IV_SUCCESS != status) { ++ ALOGE("Error in setting number of cores: 0x%x", ++ s_set_cores_op.u4_error_code); ++ return UNKNOWN_ERROR; ++ } ++ return OK; ++} ++ ++status_t SoftMPEG2::setFlushMode() { ++ IV_API_CALL_STATUS_T status; ++ ivd_ctl_flush_ip_t s_video_flush_ip; ++ ivd_ctl_flush_op_t s_video_flush_op; ++ ++ s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH; ++ s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t); ++ s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t); ++ ++ /* Set the decoder in Flush mode, subsequent decode() calls will flush */ ++ status = ivdec_api_function( ++ mCodecCtx, (void *)&s_video_flush_ip, (void *)&s_video_flush_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status, ++ s_video_flush_op.u4_error_code); ++ return UNKNOWN_ERROR; ++ } ++ ++ mWaitForI = true; ++ mIsInFlush = true; ++ return OK; ++} ++ ++status_t SoftMPEG2::initDecoder() { ++ IV_API_CALL_STATUS_T status; ++ ++ UWORD32 u4_num_reorder_frames; ++ UWORD32 u4_num_ref_frames; ++ UWORD32 u4_share_disp_buf; ++ ++ mNumCores = GetCPUCoreCount(); ++ mWaitForI = true; ++ ++ /* Initialize number of ref and reorder modes (for MPEG2) */ ++ u4_num_reorder_frames = 16; ++ u4_num_ref_frames = 16; ++ u4_share_disp_buf = 0; ++ ++ uint32_t displayStride = outputBufferWidth(); ++ uint32_t displayHeight = outputBufferHeight(); ++ uint32_t displaySizeY = displayStride * displayHeight; ++ ++ { ++ iv_num_mem_rec_ip_t s_num_mem_rec_ip; ++ iv_num_mem_rec_op_t s_num_mem_rec_op; ++ ++ s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip); ++ s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op); ++ s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC; ++ ++ status = ivdec_api_function( ++ mCodecCtx, (void *)&s_num_mem_rec_ip, (void *)&s_num_mem_rec_op); ++ if (IV_SUCCESS != status) { ++ ALOGE("Error in getting mem records: 0x%x", ++ s_num_mem_rec_op.u4_error_code); ++ return UNKNOWN_ERROR; ++ } ++ ++ mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec; ++ } ++ ++ mMemRecords = (iv_mem_rec_t *)ivd_aligned_malloc( ++ 128, mNumMemRecords * sizeof(iv_mem_rec_t)); ++ if (mMemRecords == NULL) { ++ ALOGE("Allocation failure"); ++ return NO_MEMORY; ++ } ++ ++ memset(mMemRecords, 0, mNumMemRecords * sizeof(iv_mem_rec_t)); ++ ++ { ++ size_t i; ++ ivdext_fill_mem_rec_ip_t s_fill_mem_ip; ++ ivdext_fill_mem_rec_op_t s_fill_mem_op; ++ iv_mem_rec_t *ps_mem_rec; ++ ++ s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size = ++ sizeof(ivdext_fill_mem_rec_ip_t); ++ ++ s_fill_mem_ip.u4_share_disp_buf = u4_share_disp_buf; ++ s_fill_mem_ip.e_output_format = mIvColorFormat; ++ s_fill_mem_ip.u4_deinterlace = 1; ++ s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC; ++ s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords; ++ s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = displayStride; ++ s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = displayHeight; ++ s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size = ++ sizeof(ivdext_fill_mem_rec_op_t); ++ ++ ps_mem_rec = mMemRecords; ++ for (i = 0; i < mNumMemRecords; i++) { ++ ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t); ++ } ++ ++ status = ivdec_api_function( ++ mCodecCtx, (void *)&s_fill_mem_ip, (void *)&s_fill_mem_op); ++ ++ if (IV_SUCCESS != status) { ++ ALOGE("Error in filling mem records: 0x%x", ++ s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code); ++ return UNKNOWN_ERROR; ++ } ++ mNumMemRecords = ++ s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled; ++ ++ ps_mem_rec = mMemRecords; ++ ++ for (i = 0; i < mNumMemRecords; i++) { ++ ps_mem_rec->pv_base = ivd_aligned_malloc( ++ ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size); ++ if (ps_mem_rec->pv_base == NULL) { ++ ALOGE("Allocation failure for memory record #%zu of size %u", ++ i, ps_mem_rec->u4_mem_size); ++ status = IV_FAIL; ++ return NO_MEMORY; ++ } ++ ++ ps_mem_rec++; ++ } ++ } ++ ++ /* Initialize the decoder */ ++ { ++ ivdext_init_ip_t s_init_ip; ++ ivdext_init_op_t s_init_op; ++ ++ void *dec_fxns = (void *)ivdec_api_function; ++ ++ s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t); ++ s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT; ++ s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords; ++ s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = displayStride; ++ s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = displayHeight; ++ ++ s_init_ip.u4_share_disp_buf = u4_share_disp_buf; ++ s_init_ip.u4_deinterlace = 1; ++ ++ s_init_op.s_ivd_init_op_t.u4_size = sizeof(s_init_op); ++ ++ s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords; ++ s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorFormat; ++ ++ mCodecCtx = (iv_obj_t *)mMemRecords[0].pv_base; ++ mCodecCtx->pv_fxns = dec_fxns; ++ mCodecCtx->u4_size = sizeof(iv_obj_t); ++ ++ status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip, (void *)&s_init_op); ++ if (status != IV_SUCCESS) { ++ ALOGE("Error in init: 0x%x", ++ s_init_op.s_ivd_init_op_t.u4_error_code); ++ return UNKNOWN_ERROR; ++ } ++ } ++ ++ /* Reset the plugin state */ ++ resetPlugin(); ++ ++ /* Set the run time (dynamic) parameters */ ++ mStride = outputBufferWidth(); ++ setParams(mStride); ++ ++ /* Set number of cores/threads to be used by the codec */ ++ setNumCores(); ++ ++ /* Get codec version */ ++ logVersion(); ++ ++ /* Allocate internal picture buffer */ ++ uint32_t bufferSize = displaySizeY * 3 / 2; ++ mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, bufferSize); ++ if (NULL == mFlushOutBuffer) { ++ ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize); ++ return NO_MEMORY; ++ } ++ ++ mInitNeeded = false; ++ mFlushNeeded = false; ++ return OK; ++} ++ ++status_t SoftMPEG2::deInitDecoder() { ++ size_t i; ++ ++ if (mMemRecords) { ++ iv_mem_rec_t *ps_mem_rec; ++ ++ ps_mem_rec = mMemRecords; ++ for (i = 0; i < mNumMemRecords; i++) { ++ if (ps_mem_rec->pv_base) { ++ ivd_aligned_free(ps_mem_rec->pv_base); ++ } ++ ps_mem_rec++; ++ } ++ ivd_aligned_free(mMemRecords); ++ mMemRecords = NULL; ++ } ++ ++ if (mFlushOutBuffer) { ++ ivd_aligned_free(mFlushOutBuffer); ++ mFlushOutBuffer = NULL; ++ } ++ ++ mInitNeeded = true; ++ mChangingResolution = false; ++ mCodecCtx = NULL; ++ ++ return OK; ++} ++ ++status_t SoftMPEG2::reInitDecoder() { ++ status_t ret; ++ ++ deInitDecoder(); ++ ++ ret = initDecoder(); ++ if (OK != ret) { ++ ALOGE("Failed to initialize decoder"); ++ deInitDecoder(); ++ return ret; ++ } ++ mSignalledError = false; ++ return OK; ++} ++ ++void SoftMPEG2::onReset() { ++ SoftVideoDecoderOMXComponent::onReset(); ++ ++ mWaitForI = true; ++ ++ resetDecoder(); ++ resetPlugin(); ++} ++ ++bool SoftMPEG2::getSeqInfo() { ++ IV_API_CALL_STATUS_T status; ++ impeg2d_ctl_get_seq_info_ip_t s_ctl_get_seq_info_ip; ++ impeg2d_ctl_get_seq_info_op_t s_ctl_get_seq_info_op; ++ ++ s_ctl_get_seq_info_ip.e_cmd = IVD_CMD_VIDEO_CTL; ++ s_ctl_get_seq_info_ip.e_sub_cmd = ++ (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_GET_SEQ_INFO; ++ ++ s_ctl_get_seq_info_ip.u4_size = sizeof(impeg2d_ctl_get_seq_info_ip_t); ++ s_ctl_get_seq_info_op.u4_size = sizeof(impeg2d_ctl_get_seq_info_op_t); ++ ++ status = ivdec_api_function( ++ (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_seq_info_ip, ++ (void *)&s_ctl_get_seq_info_op); ++ ++ if (status != IV_SUCCESS) { ++ ALOGW("Error in getting Sequence info: 0x%x", ++ s_ctl_get_seq_info_op.u4_error_code); ++ return false; ++ } ++ ++ ++ int32_t primaries = s_ctl_get_seq_info_op.u1_colour_primaries; ++ int32_t transfer = s_ctl_get_seq_info_op.u1_transfer_characteristics; ++ int32_t coeffs = s_ctl_get_seq_info_op.u1_matrix_coefficients; ++ bool fullRange = false; // mpeg2 video has limited range. ++ ++ ColorAspects colorAspects; ++ ColorUtils::convertIsoColorAspectsToCodecAspects( ++ primaries, transfer, coeffs, fullRange, colorAspects); ++ ++ // Update color aspects if necessary. ++ if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) { ++ mBitstreamColorAspects = colorAspects; ++ status_t err = handleColorAspectsChange(); ++ CHECK(err == OK); ++ } ++ return true; ++} ++ ++OMX_ERRORTYPE SoftMPEG2::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) { ++ const uint32_t oldWidth = mWidth; ++ const uint32_t oldHeight = mHeight; ++ OMX_ERRORTYPE ret = SoftVideoDecoderOMXComponent::internalSetParameter(index, params); ++ if (mWidth != oldWidth || mHeight != oldHeight) { ++ reInitDecoder(); ++ } ++ return ret; ++} ++ ++bool SoftMPEG2::setDecodeArgs( ++ ivd_video_decode_ip_t *ps_dec_ip, ++ ivd_video_decode_op_t *ps_dec_op, ++ OMX_BUFFERHEADERTYPE *inHeader, ++ OMX_BUFFERHEADERTYPE *outHeader, ++ size_t timeStampIx) { ++ size_t sizeY = outputBufferWidth() * outputBufferHeight(); ++ size_t sizeUV; ++ ++ ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t); ++ ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t); ++ ++ ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE; ++ ++ /* When in flush and after EOS with zero byte input, ++ * inHeader is set to zero. Hence check for non-null */ ++ if (inHeader) { ++ ps_dec_ip->u4_ts = timeStampIx; ++ ps_dec_ip->pv_stream_buffer = inHeader->pBuffer ++ + inHeader->nOffset; ++ ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen; ++ } else { ++ ps_dec_ip->u4_ts = 0; ++ ps_dec_ip->pv_stream_buffer = NULL; ++ ps_dec_ip->u4_num_Bytes = 0; ++ } ++ ++ sizeUV = sizeY / 4; ++ ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY; ++ ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV; ++ ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV; ++ ++ uint8_t *pBuf; ++ if (outHeader) { ++ if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) { ++ android_errorWriteLog(0x534e4554, "27833616"); ++ return false; ++ } ++ pBuf = outHeader->pBuffer; ++ } else { ++ // mFlushOutBuffer always has the right size. ++ pBuf = mFlushOutBuffer; ++ } ++ ++ ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf; ++ ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY; ++ ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV; ++ ps_dec_ip->s_out_buffer.u4_num_bufs = 3; ++ return true; ++} ++void SoftMPEG2::onPortFlushCompleted(OMX_U32 portIndex) { ++ /* Once the output buffers are flushed, ignore any buffers that are held in decoder */ ++ if (kOutputPortIndex == portIndex) { ++ setFlushMode(); ++ ++ while (true) { ++ ivd_video_decode_ip_t s_dec_ip; ++ ivd_video_decode_op_t s_dec_op; ++ IV_API_CALL_STATUS_T status; ++ size_t sizeY, sizeUV; ++ ++ setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0); ++ ++ status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); ++ if (0 == s_dec_op.u4_output_present) { ++ resetPlugin(); ++ break; ++ } ++ } ++ } ++} ++ ++void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) { ++ UNUSED(portIndex); ++ ++ if (mSignalledError) { ++ return; ++ } ++ if (mOutputPortSettingsChange != NONE) { ++ return; ++ } ++ ++ if (NULL == mCodecCtx) { ++ if (OK != initDecoder()) { ++ ALOGE("Failed to initialize decoder"); ++ notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ } ++ ++ List &inQueue = getPortQueue(kInputPortIndex); ++ List &outQueue = getPortQueue(kOutputPortIndex); ++ ++ if (outputBufferWidth() != mStride) { ++ /* Set the run-time (dynamic) parameters */ ++ mStride = outputBufferWidth(); ++ setParams(mStride); ++ } ++ ++ while (!outQueue.empty()) { ++ BufferInfo *inInfo; ++ OMX_BUFFERHEADERTYPE *inHeader; ++ ++ BufferInfo *outInfo; ++ OMX_BUFFERHEADERTYPE *outHeader; ++ size_t timeStampIx; ++ ++ inInfo = NULL; ++ inHeader = NULL; ++ ++ if (!mIsInFlush) { ++ if (!inQueue.empty()) { ++ inInfo = *inQueue.begin(); ++ inHeader = inInfo->mHeader; ++ } else { ++ break; ++ } ++ } ++ ++ outInfo = *outQueue.begin(); ++ outHeader = outInfo->mHeader; ++ outHeader->nFlags = 0; ++ outHeader->nTimeStamp = 0; ++ outHeader->nOffset = 0; ++ ++ if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) { ++ mReceivedEOS = true; ++ if (inHeader->nFilledLen == 0) { ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ setFlushMode(); ++ } ++ } ++ ++ // When there is an init required and the decoder is not in flush mode, ++ // update output port's definition and reinitialize decoder. ++ if (mInitNeeded && !mIsInFlush) { ++ bool portWillReset = false; ++ handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight); ++ ++ if (OK != reInitDecoder()) { ++ ALOGE("Failed to reinitialize decoder"); ++ } ++ return; ++ } ++ ++ /* Get a free slot in timestamp array to hold input timestamp */ ++ { ++ size_t i; ++ timeStampIx = 0; ++ for (i = 0; i < MAX_TIME_STAMPS; i++) { ++ if (!mTimeStampsValid[i]) { ++ timeStampIx = i; ++ break; ++ } ++ } ++ if (inHeader != NULL) { ++ mTimeStampsValid[timeStampIx] = true; ++ mTimeStamps[timeStampIx] = inHeader->nTimeStamp; ++ } ++ } ++ ++ { ++ ivd_video_decode_ip_t s_dec_ip; ++ ivd_video_decode_op_t s_dec_op; ++ WORD32 timeDelay, timeTaken; ++ size_t sizeY, sizeUV; ++ ++ if (!setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) { ++ ALOGE("Decoder arg setup failed"); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ // If input dump is enabled, then write to file ++ DUMP_TO_FILE(mInFile, s_dec_ip.pv_stream_buffer, s_dec_ip.u4_num_Bytes); ++ ++ if (s_dec_ip.u4_num_Bytes > 0) { ++ char *ptr = (char *)s_dec_ip.pv_stream_buffer; ++ } ++ ++ GETTIME(&mTimeStart, NULL); ++ /* Compute time elapsed between end of previous decode() ++ * to start of current decode() */ ++ TIME_DIFF(mTimeEnd, mTimeStart, timeDelay); ++ ++ IV_API_CALL_STATUS_T status; ++ status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); ++ ++ bool unsupportedDimensions = (IMPEG2D_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code); ++ bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF)); ++ ++ getSeqInfo(); ++ ++ GETTIME(&mTimeEnd, NULL); ++ /* Compute time taken for decode() */ ++ TIME_DIFF(mTimeStart, mTimeEnd, timeTaken); ++ ++ ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, ++ s_dec_op.u4_num_bytes_consumed); ++ if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) { ++ mFlushNeeded = true; ++ } ++ ++ if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) { ++ /* If the input did not contain picture data, then ignore ++ * the associated timestamp */ ++ mTimeStampsValid[timeStampIx] = false; ++ } ++ ++ // This is needed to handle CTS DecoderTest testCodecResetsMPEG2WithoutSurface, ++ // which is not sending SPS/PPS after port reconfiguration and flush to the codec. ++ if (unsupportedDimensions && !mFlushNeeded) { ++ bool portWillReset = false; ++ handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht); ++ ++ if (OK != reInitDecoder()) { ++ ALOGE("Failed to reinitialize decoder"); ++ return; ++ } ++ ++ if (setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) { ++ ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); ++ } ++ return; ++ } ++ ++ // If the decoder is in the changing resolution mode and there is no output present, ++ // that means the switching is done and it's ready to reset the decoder and the plugin. ++ if (mChangingResolution && !s_dec_op.u4_output_present) { ++ mChangingResolution = false; ++ resetDecoder(); ++ resetPlugin(); ++ mStride = outputBufferWidth(); ++ setParams(mStride); ++ continue; ++ } ++ ++ if (unsupportedDimensions || resChanged) { ++ mChangingResolution = true; ++ if (mFlushNeeded) { ++ setFlushMode(); ++ } ++ ++ if (unsupportedDimensions) { ++ mNewWidth = s_dec_op.u4_pic_wd; ++ mNewHeight = s_dec_op.u4_pic_ht; ++ mInitNeeded = true; ++ } ++ continue; ++ } ++ ++ // Combine the resolution change and coloraspects change in one PortSettingChange event ++ // if necessary. ++ if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) { ++ uint32_t width = s_dec_op.u4_pic_wd; ++ uint32_t height = s_dec_op.u4_pic_ht; ++ bool portWillReset = false; ++ handlePortSettingsChange(&portWillReset, width, height); ++ ++ if (portWillReset) { ++ resetDecoder(); ++ resetPlugin(); ++ return; ++ } ++ } else if (mUpdateColorAspects) { ++ notify(OMX_EventPortSettingsChanged, kOutputPortIndex, ++ kDescribeColorAspectsIndex, NULL); ++ mUpdateColorAspects = false; ++ return; ++ } ++ ++ if (s_dec_op.u4_output_present) { ++ ssize_t timeStampIdx; ++ outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2; ++ ++ timeStampIdx = getMinTimestampIdx(mTimeStamps, mTimeStampsValid); ++ if (timeStampIdx < 0) { ++ ALOGE("b/62872863, Invalid timestamp index!"); ++ android_errorWriteLog(0x534e4554, "62872863"); ++ return; ++ } ++ outHeader->nTimeStamp = mTimeStamps[timeStampIdx]; ++ mTimeStampsValid[timeStampIdx] = false; ++ ++ /* mWaitForI waits for the first I picture. Once made FALSE, it ++ has to remain false till explicitly set to TRUE. */ ++ mWaitForI = mWaitForI && !(IV_I_FRAME == s_dec_op.e_pic_type); ++ ++ if (mWaitForI) { ++ s_dec_op.u4_output_present = false; ++ } else { ++ ALOGV("Output timestamp: %lld, res: %ux%u", ++ (long long)outHeader->nTimeStamp, mWidth, mHeight); ++ DUMP_TO_FILE(mOutFile, outHeader->pBuffer, outHeader->nFilledLen); ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ outInfo = NULL; ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ } ++ } else if (mIsInFlush) { ++ /* If in flush mode and no output is returned by the codec, ++ * then come out of flush mode */ ++ mIsInFlush = false; ++ ++ /* If EOS was recieved on input port and there is no output ++ * from the codec, then signal EOS on output port */ ++ if (mReceivedEOS) { ++ outHeader->nFilledLen = 0; ++ outHeader->nFlags |= OMX_BUFFERFLAG_EOS; ++ ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ outInfo = NULL; ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ resetPlugin(); ++ } ++ } ++ } ++ ++ /* If input EOS is seen and decoder is not in flush mode, ++ * set the decoder in flush mode. ++ * There can be a case where EOS is sent along with last picture data ++ * In that case, only after decoding that input data, decoder has to be ++ * put in flush. This case is handled here */ ++ ++ if (mReceivedEOS && !mIsInFlush) { ++ setFlushMode(); ++ } ++ ++ // TODO: Handle more than one picture data ++ if (inHeader != NULL) { ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ } ++ } ++} ++ ++int SoftMPEG2::getColorAspectPreference() { ++ return kPreferBitstream; ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) { ++ return new android::SoftMPEG2(name, callbacks, appData, component); ++} +diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h +new file mode 100644 +index 0000000..338fc30 +--- /dev/null ++++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h +@@ -0,0 +1,184 @@ ++/* ++ * Copyright 2015 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 SOFT_MPEG2_H_ ++ ++#define SOFT_MPEG2_H_ ++ ++#include ++#include ++ ++namespace android { ++ ++#define ivd_aligned_malloc(alignment, size) memalign(alignment, size) ++#define ivd_aligned_free(buf) free(buf) ++ ++/** Number of entries in the time-stamp array */ ++#define MAX_TIME_STAMPS 64 ++ ++/** Maximum number of cores supported by the codec */ ++#define CODEC_MAX_NUM_CORES 4 ++ ++#define CODEC_MAX_WIDTH 1920 ++ ++#define CODEC_MAX_HEIGHT 1088 ++ ++/** Input buffer size */ ++#define INPUT_BUF_SIZE (1024 * 1024) ++ ++#define MIN(a, b) ((a) < (b)) ? (a) : (b) ++ ++/** Used to remove warnings about unused parameters */ ++#define UNUSED(x) ((void)(x)) ++ ++/** Get time */ ++#define GETTIME(a, b) gettimeofday(a, b); ++ ++/** Compute difference between start and end */ ++#define TIME_DIFF(start, end, diff) \ ++ diff = (((end).tv_sec - (start).tv_sec) * 1000000) + \ ++ ((end).tv_usec - (start).tv_usec); ++ ++struct SoftMPEG2 : public SoftVideoDecoderOMXComponent { ++ SoftMPEG2( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component); ++ ++protected: ++ virtual ~SoftMPEG2(); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ virtual void onPortFlushCompleted(OMX_U32 portIndex); ++ virtual void onReset(); ++ virtual int getColorAspectPreference(); ++ virtual OMX_ERRORTYPE internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params); ++private: ++ // Number of input and output buffers ++ enum { ++ kNumBuffers = 8 ++ }; ++ ++ iv_obj_t *mCodecCtx; // Codec context ++ iv_mem_rec_t *mMemRecords; // Memory records requested by the codec ++ size_t mNumMemRecords; // Number of memory records requested by the codec ++ ++ size_t mNumCores; // Number of cores to be uesd by the codec ++ ++ struct timeval mTimeStart; // Time at the start of decode() ++ struct timeval mTimeEnd; // Time at the end of decode() ++ ++ // Internal buffer to be used to flush out the buffers from decoder ++ uint8_t *mFlushOutBuffer; ++ ++ // Status of entries in the timestamp array ++ bool mTimeStampsValid[MAX_TIME_STAMPS]; ++ ++ // Timestamp array - Since codec does not take 64 bit timestamps, ++ // they are maintained in the plugin ++ OMX_S64 mTimeStamps[MAX_TIME_STAMPS]; ++ ++#ifdef FILE_DUMP_ENABLE ++ char mInFile[200]; ++#endif /* FILE_DUMP_ENABLE */ ++ ++ OMX_COLOR_FORMATTYPE mOmxColorFormat; // OMX Color format ++ IV_COLOR_FORMAT_T mIvColorFormat; // Ittiam Color format ++ ++ bool mIsInFlush; // codec is flush mode ++ bool mReceivedEOS; // EOS is receieved on input port ++ bool mInitNeeded; ++ uint32_t mNewWidth; ++ uint32_t mNewHeight; ++ // The input stream has changed to a different resolution, which is still supported by the ++ // codec. So the codec is switching to decode the new resolution. ++ bool mChangingResolution; ++ bool mFlushNeeded; ++ bool mSignalledError; ++ bool mWaitForI; ++ size_t mStride; ++ ++ status_t initDecoder(); ++ status_t deInitDecoder(); ++ status_t setFlushMode(); ++ status_t setParams(size_t stride); ++ void logVersion(); ++ status_t setNumCores(); ++ status_t resetDecoder(); ++ status_t resetPlugin(); ++ status_t reInitDecoder(); ++ ++ bool setDecodeArgs( ++ ivd_video_decode_ip_t *ps_dec_ip, ++ ivd_video_decode_op_t *ps_dec_op, ++ OMX_BUFFERHEADERTYPE *inHeader, ++ OMX_BUFFERHEADERTYPE *outHeader, ++ size_t timeStampIx); ++ ++ bool getSeqInfo(); ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftMPEG2); ++}; ++ ++#ifdef FILE_DUMP_ENABLE ++ ++#define INPUT_DUMP_PATH "/sdcard/media/mpeg2d_input" ++#define INPUT_DUMP_EXT "m2v" ++ ++#define GENERATE_FILE_NAMES() { \ ++ GETTIME(&mTimeStart, NULL); \ ++ strcpy(mInFile, ""); \ ++ sprintf(mInFile, "%s_%ld.%ld.%s", INPUT_DUMP_PATH, \ ++ mTimeStart.tv_sec, mTimeStart.tv_usec, \ ++ INPUT_DUMP_EXT); \ ++} ++ ++#define CREATE_DUMP_FILE(m_filename) { \ ++ FILE *fp = fopen(m_filename, "wb"); \ ++ if (fp != NULL) { \ ++ fclose(fp); \ ++ } else { \ ++ ALOGD("Could not open file %s", m_filename); \ ++ } \ ++} ++#define DUMP_TO_FILE(m_filename, m_buf, m_size) \ ++{ \ ++ FILE *fp = fopen(m_filename, "ab"); \ ++ if (fp != NULL && m_buf != NULL) { \ ++ int i; \ ++ i = fwrite(m_buf, 1, m_size, fp); \ ++ ALOGD("fwrite ret %d to write %d", i, m_size); \ ++ if (i != (int)m_size) { \ ++ ALOGD("Error in fwrite, returned %d", i); \ ++ perror("Error in write to file"); \ ++ } \ ++ fclose(fp); \ ++ } else { \ ++ ALOGD("Could not write to file %s", m_filename);\ ++ } \ ++} ++#else /* FILE_DUMP_ENABLE */ ++#define INPUT_DUMP_PATH ++#define INPUT_DUMP_EXT ++#define OUTPUT_DUMP_PATH ++#define OUTPUT_DUMP_EXT ++#define GENERATE_FILE_NAMES() ++#define CREATE_DUMP_FILE(m_filename) ++#define DUMP_TO_FILE(m_filename, m_buf, m_size) ++#endif /* FILE_DUMP_ENABLE */ ++ ++} // namespace android ++ ++#endif // SOFT_MPEG2_H_ +diff --git a/media/libstagefright/codecs/mpeg2dec/exports.lds b/media/libstagefright/codecs/mpeg2dec/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/mpeg2dec/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/on2/dec/Android.bp b/media/libstagefright/codecs/on2/dec/Android.bp +new file mode 100644 +index 0000000..ba6dc2a +--- /dev/null ++++ b/media/libstagefright/codecs/on2/dec/Android.bp +@@ -0,0 +1,37 @@ ++package { ++ default_applicable_licenses: [ ++ "frameworks_av_media_libstagefright_codecs_on2_dec_license", ++ ], ++} ++ ++// Added automatically by a large-scale-change ++// See: http://go/android-license-faq ++license { ++ name: "frameworks_av_media_libstagefright_codecs_on2_dec_license", ++ visibility: [":__subpackages__"], ++ license_kinds: [ ++ "SPDX-license-identifier-Apache-2.0", ++ ], ++ license_text: [ ++ "NOTICE", ++ ], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_vpxdec", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: ["SoftVPX.cpp"], ++ ++ shared_libs: ["libvpx"], ++ ++ version_script: "exports.lds", ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ "unsigned-integer-overflow", ++ ], ++ cfi: true, ++ }, ++} +diff --git a/media/libstagefright/codecs/on2/dec/MODULE_LICENSE_APACHE2 b/media/libstagefright/codecs/on2/dec/MODULE_LICENSE_APACHE2 +new file mode 100644 +index 0000000..e69de29 +diff --git a/media/libstagefright/codecs/on2/dec/NOTICE b/media/libstagefright/codecs/on2/dec/NOTICE +new file mode 100644 +index 0000000..c5b1efa +--- /dev/null ++++ b/media/libstagefright/codecs/on2/dec/NOTICE +@@ -0,0 +1,190 @@ ++ ++ Copyright (c) 2005-2008, 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. ++ ++ 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. ++ ++ ++ Apache License ++ Version 2.0, January 2004 ++ http://www.apache.org/licenses/ ++ ++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION ++ ++ 1. Definitions. ++ ++ "License" shall mean the terms and conditions for use, reproduction, ++ and distribution as defined by Sections 1 through 9 of this document. ++ ++ "Licensor" shall mean the copyright owner or entity authorized by ++ the copyright owner that is granting the License. ++ ++ "Legal Entity" shall mean the union of the acting entity and all ++ other entities that control, are controlled by, or are under common ++ control with that entity. For the purposes of this definition, ++ "control" means (i) the power, direct or indirect, to cause the ++ direction or management of such entity, whether by contract or ++ otherwise, or (ii) ownership of fifty percent (50%) or more of the ++ outstanding shares, or (iii) beneficial ownership of such entity. ++ ++ "You" (or "Your") shall mean an individual or Legal Entity ++ exercising permissions granted by this License. ++ ++ "Source" form shall mean the preferred form for making modifications, ++ including but not limited to software source code, documentation ++ source, and configuration files. ++ ++ "Object" form shall mean any form resulting from mechanical ++ transformation or translation of a Source form, including but ++ not limited to compiled object code, generated documentation, ++ and conversions to other media types. ++ ++ "Work" shall mean the work of authorship, whether in Source or ++ Object form, made available under the License, as indicated by a ++ copyright notice that is included in or attached to the work ++ (an example is provided in the Appendix below). ++ ++ "Derivative Works" shall mean any work, whether in Source or Object ++ form, that is based on (or derived from) the Work and for which the ++ editorial revisions, annotations, elaborations, or other modifications ++ represent, as a whole, an original work of authorship. For the purposes ++ of this License, Derivative Works shall not include works that remain ++ separable from, or merely link (or bind by name) to the interfaces of, ++ the Work and Derivative Works thereof. ++ ++ "Contribution" shall mean any work of authorship, including ++ the original version of the Work and any modifications or additions ++ to that Work or Derivative Works thereof, that is intentionally ++ submitted to Licensor for inclusion in the Work by the copyright owner ++ or by an individual or Legal Entity authorized to submit on behalf of ++ the copyright owner. For the purposes of this definition, "submitted" ++ means any form of electronic, verbal, or written communication sent ++ to the Licensor or its representatives, including but not limited to ++ communication on electronic mailing lists, source code control systems, ++ and issue tracking systems that are managed by, or on behalf of, the ++ Licensor for the purpose of discussing and improving the Work, but ++ excluding communication that is conspicuously marked or otherwise ++ designated in writing by the copyright owner as "Not a Contribution." ++ ++ "Contributor" shall mean Licensor and any individual or Legal Entity ++ on behalf of whom a Contribution has been received by Licensor and ++ subsequently incorporated within the Work. ++ ++ 2. Grant of Copyright License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ copyright license to reproduce, prepare Derivative Works of, ++ publicly display, publicly perform, sublicense, and distribute the ++ Work and such Derivative Works in Source or Object form. ++ ++ 3. Grant of Patent License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ (except as stated in this section) patent license to make, have made, ++ use, offer to sell, sell, import, and otherwise transfer the Work, ++ where such license applies only to those patent claims licensable ++ by such Contributor that are necessarily infringed by their ++ Contribution(s) alone or by combination of their Contribution(s) ++ with the Work to which such Contribution(s) was submitted. If You ++ institute patent litigation against any entity (including a ++ cross-claim or counterclaim in a lawsuit) alleging that the Work ++ or a Contribution incorporated within the Work constitutes direct ++ or contributory patent infringement, then any patent licenses ++ granted to You under this License for that Work shall terminate ++ as of the date such litigation is filed. ++ ++ 4. Redistribution. You may reproduce and distribute copies of the ++ Work or Derivative Works thereof in any medium, with or without ++ modifications, and in Source or Object form, provided that You ++ meet the following conditions: ++ ++ (a) You must give any other recipients of the Work or ++ Derivative Works a copy of this License; and ++ ++ (b) You must cause any modified files to carry prominent notices ++ stating that You changed the files; and ++ ++ (c) You must retain, in the Source form of any Derivative Works ++ that You distribute, all copyright, patent, trademark, and ++ attribution notices from the Source form of the Work, ++ excluding those notices that do not pertain to any part of ++ the Derivative Works; and ++ ++ (d) If the Work includes a "NOTICE" text file as part of its ++ distribution, then any Derivative Works that You distribute must ++ include a readable copy of the attribution notices contained ++ within such NOTICE file, excluding those notices that do not ++ pertain to any part of the Derivative Works, in at least one ++ of the following places: within a NOTICE text file distributed ++ as part of the Derivative Works; within the Source form or ++ documentation, if provided along with the Derivative Works; or, ++ within a display generated by the Derivative Works, if and ++ wherever such third-party notices normally appear. The contents ++ of the NOTICE file are for informational purposes only and ++ do not modify the License. You may add Your own attribution ++ notices within Derivative Works that You distribute, alongside ++ or as an addendum to the NOTICE text from the Work, provided ++ that such additional attribution notices cannot be construed ++ as modifying the License. ++ ++ You may add Your own copyright statement to Your modifications and ++ may provide additional or different license terms and conditions ++ for use, reproduction, or distribution of Your modifications, or ++ for any such Derivative Works as a whole, provided Your use, ++ reproduction, and distribution of the Work otherwise complies with ++ the conditions stated in this License. ++ ++ 5. Submission of Contributions. Unless You explicitly state otherwise, ++ any Contribution intentionally submitted for inclusion in the Work ++ by You to the Licensor shall be under the terms and conditions of ++ this License, without any additional terms or conditions. ++ Notwithstanding the above, nothing herein shall supersede or modify ++ the terms of any separate license agreement you may have executed ++ with Licensor regarding such Contributions. ++ ++ 6. Trademarks. This License does not grant permission to use the trade ++ names, trademarks, service marks, or product names of the Licensor, ++ except as required for reasonable and customary use in describing the ++ origin of the Work and reproducing the content of the NOTICE file. ++ ++ 7. Disclaimer of Warranty. Unless required by applicable law or ++ agreed to in writing, Licensor provides the Work (and each ++ Contributor provides its Contributions) on an "AS IS" BASIS, ++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or ++ implied, including, without limitation, any warranties or conditions ++ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A ++ PARTICULAR PURPOSE. You are solely responsible for determining the ++ appropriateness of using or redistributing the Work and assume any ++ risks associated with Your exercise of permissions under this License. ++ ++ 8. Limitation of Liability. In no event and under no legal theory, ++ whether in tort (including negligence), contract, or otherwise, ++ unless required by applicable law (such as deliberate and grossly ++ negligent acts) or agreed to in writing, shall any Contributor be ++ liable to You for damages, including any direct, indirect, special, ++ incidental, or consequential damages of any character arising as a ++ result of this License or out of the use or inability to use the ++ Work (including but not limited to damages for loss of goodwill, ++ work stoppage, computer failure or malfunction, or any and all ++ other commercial damages or losses), even if such Contributor ++ has been advised of the possibility of such damages. ++ ++ 9. Accepting Warranty or Additional Liability. While redistributing ++ the Work or Derivative Works thereof, You may choose to offer, ++ and charge a fee for, acceptance of support, warranty, indemnity, ++ or other liability obligations and/or rights consistent with this ++ License. However, in accepting such obligations, You may act only ++ on Your own behalf and on Your sole responsibility, not on behalf ++ of any other Contributor, and only if You agree to indemnify, ++ defend, and hold each Contributor harmless for any liability ++ incurred by, or claims asserted against, such Contributor by reason ++ of your accepting any such warranty or additional liability. ++ ++ END OF TERMS AND CONDITIONS ++ +diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp +new file mode 100644 +index 0000000..bffc23a +--- /dev/null ++++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp +@@ -0,0 +1,374 @@ ++/* ++ * Copyright (C) 2011 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 "SoftVPX" ++#include ++#include ++#include "OMX_VideoExt.h" ++ ++#include "SoftVPX.h" ++ ++#include ++#include ++ ++ ++namespace android { ++ ++// Only need to declare the highest supported profile and level here. ++static const CodecProfileLevel kVP9ProfileLevels[] = { ++ { OMX_VIDEO_VP9Profile0, OMX_VIDEO_VP9Level5 }, ++ { OMX_VIDEO_VP9Profile2, OMX_VIDEO_VP9Level5 }, ++ { OMX_VIDEO_VP9Profile2HDR, OMX_VIDEO_VP9Level5 }, ++ { OMX_VIDEO_VP9Profile2HDR10Plus, OMX_VIDEO_VP9Level5 }, ++}; ++ ++SoftVPX::SoftVPX( ++ const char *name, ++ const char *componentRole, ++ OMX_VIDEO_CODINGTYPE codingType, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SoftVideoDecoderOMXComponent( ++ name, componentRole, codingType, ++ codingType == OMX_VIDEO_CodingVP8 ? NULL : kVP9ProfileLevels, ++ codingType == OMX_VIDEO_CodingVP8 ? 0 : NELEM(kVP9ProfileLevels), ++ 320 /* width */, 240 /* height */, callbacks, appData, component), ++ mMode(codingType == OMX_VIDEO_CodingVP8 ? MODE_VP8 : MODE_VP9), ++ mEOSStatus(INPUT_DATA_AVAILABLE), ++ mCtx(NULL), ++ mFrameParallelMode(false), ++ mTimeStampIdx(0), ++ mImg(NULL) { ++ // arbitrary from avc/hevc as vpx does not specify a min compression ratio ++ const size_t kMinCompressionRatio = mMode == MODE_VP8 ? 2 : 4; ++ const char *mime = mMode == MODE_VP8 ? MEDIA_MIMETYPE_VIDEO_VP8 : MEDIA_MIMETYPE_VIDEO_VP9; ++ const size_t kMaxOutputBufferSize = 2048 * 2048 * 3 / 2; ++ initPorts( ++ kNumBuffers, kMaxOutputBufferSize / kMinCompressionRatio /* inputBufferSize */, ++ kNumBuffers, mime, kMinCompressionRatio); ++ CHECK_EQ(initDecoder(), (status_t)OK); ++} ++ ++SoftVPX::~SoftVPX() { ++ destroyDecoder(); ++} ++ ++static int GetCPUCoreCount() { ++ int cpuCoreCount = 1; ++#if defined(_SC_NPROCESSORS_ONLN) ++ cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); ++#else ++ // _SC_NPROC_ONLN must be defined... ++ cpuCoreCount = sysconf(_SC_NPROC_ONLN); ++#endif ++ CHECK(cpuCoreCount >= 1); ++ ALOGV("Number of CPU cores: %d", cpuCoreCount); ++ return cpuCoreCount; ++} ++ ++bool SoftVPX::supportDescribeHdrStaticInfo() { ++ return true; ++} ++ ++bool SoftVPX::supportDescribeHdr10PlusInfo() { ++ return true; ++} ++ ++status_t SoftVPX::initDecoder() { ++ mCtx = new vpx_codec_ctx_t; ++ vpx_codec_err_t vpx_err; ++ vpx_codec_dec_cfg_t cfg; ++ vpx_codec_flags_t flags; ++ memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t)); ++ memset(&flags, 0, sizeof(vpx_codec_flags_t)); ++ cfg.threads = GetCPUCoreCount(); ++ ++ if (mFrameParallelMode) { ++ flags |= VPX_CODEC_USE_FRAME_THREADING; ++ } ++ ++ if ((vpx_err = vpx_codec_dec_init( ++ (vpx_codec_ctx_t *)mCtx, ++ mMode == MODE_VP8 ? &vpx_codec_vp8_dx_algo : &vpx_codec_vp9_dx_algo, ++ &cfg, flags))) { ++ ALOGE("on2 decoder failed to initialize. (%d)", vpx_err); ++ return UNKNOWN_ERROR; ++ } ++ ++ return OK; ++} ++ ++status_t SoftVPX::destroyDecoder() { ++ vpx_codec_destroy((vpx_codec_ctx_t *)mCtx); ++ delete (vpx_codec_ctx_t *)mCtx; ++ mCtx = NULL; ++ return OK; ++} ++ ++bool SoftVPX::outputBuffers(bool flushDecoder, bool display, bool eos, bool *portWillReset) { ++ List &outQueue = getPortQueue(1); ++ BufferInfo *outInfo = NULL; ++ OMX_BUFFERHEADERTYPE *outHeader = NULL; ++ vpx_codec_iter_t iter = NULL; ++ ++ if (flushDecoder && mFrameParallelMode) { ++ // Flush decoder by passing NULL data ptr and 0 size. ++ // Ideally, this should never fail. ++ if (vpx_codec_decode((vpx_codec_ctx_t *)mCtx, NULL, 0, NULL, 0)) { ++ ALOGE("Failed to flush on2 decoder."); ++ return false; ++ } ++ } ++ ++ if (!display) { ++ if (!flushDecoder) { ++ ALOGE("Invalid operation."); ++ return false; ++ } ++ // Drop all the decoded frames in decoder. ++ while ((mImg = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter))) { ++ } ++ return true; ++ } ++ ++ while (!outQueue.empty()) { ++ if (mImg == NULL) { ++ mImg = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter); ++ if (mImg == NULL) { ++ break; ++ } ++ } ++ uint32_t width = mImg->d_w; ++ uint32_t height = mImg->d_h; ++ outInfo = *outQueue.begin(); ++ outHeader = outInfo->mHeader; ++ CHECK(mImg->fmt == VPX_IMG_FMT_I420 || mImg->fmt == VPX_IMG_FMT_I42016); ++ OMX_COLOR_FORMATTYPE outputColorFormat = OMX_COLOR_FormatYUV420Planar; ++ int32_t bpp = 1; ++ if (mImg->fmt == VPX_IMG_FMT_I42016) { ++ outputColorFormat = OMX_COLOR_FormatYUV420Planar16; ++ bpp = 2; ++ } ++ handlePortSettingsChange(portWillReset, width, height, outputColorFormat); ++ if (*portWillReset) { ++ return true; ++ } ++ ++ outHeader->nOffset = 0; ++ outHeader->nFlags = 0; ++ outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * bpp * 3) / 2; ++ PrivInfo *privInfo = (PrivInfo *)mImg->user_priv; ++ outHeader->nTimeStamp = privInfo->mTimeStamp; ++ if (privInfo->mHdr10PlusInfo != nullptr) { ++ queueOutputFrameConfig(privInfo->mHdr10PlusInfo); ++ } ++ ++ if (outputBufferSafe(outHeader)) { ++ uint8_t *dst = outHeader->pBuffer; ++ const uint8_t *srcY = (const uint8_t *)mImg->planes[VPX_PLANE_Y]; ++ const uint8_t *srcU = (const uint8_t *)mImg->planes[VPX_PLANE_U]; ++ const uint8_t *srcV = (const uint8_t *)mImg->planes[VPX_PLANE_V]; ++ size_t srcYStride = mImg->stride[VPX_PLANE_Y]; ++ size_t srcUStride = mImg->stride[VPX_PLANE_U]; ++ size_t srcVStride = mImg->stride[VPX_PLANE_V]; ++ copyYV12FrameToOutputBuffer(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride); ++ } else { ++ outHeader->nFilledLen = 0; ++ } ++ ++ mImg = NULL; ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ outInfo = NULL; ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ } ++ ++ if (!eos) { ++ return true; ++ } ++ ++ if (!outQueue.empty()) { ++ outInfo = *outQueue.begin(); ++ outQueue.erase(outQueue.begin()); ++ outHeader = outInfo->mHeader; ++ outHeader->nTimeStamp = 0; ++ outHeader->nFilledLen = 0; ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ outInfo->mOwnedByUs = false; ++ notifyFillBufferDone(outHeader); ++ mEOSStatus = OUTPUT_FRAMES_FLUSHED; ++ } ++ return true; ++} ++ ++bool SoftVPX::outputBufferSafe(OMX_BUFFERHEADERTYPE *outHeader) { ++ uint32_t width = outputBufferWidth(); ++ uint32_t height = outputBufferHeight(); ++ uint64_t nFilledLen = width; ++ nFilledLen *= height; ++ if (nFilledLen > UINT32_MAX / 3) { ++ ALOGE("b/29421675, nFilledLen overflow %llu w %u h %u", ++ (unsigned long long)nFilledLen, width, height); ++ android_errorWriteLog(0x534e4554, "29421675"); ++ return false; ++ } else if (outHeader->nAllocLen < outHeader->nFilledLen) { ++ ALOGE("b/27597103, buffer too small"); ++ android_errorWriteLog(0x534e4554, "27597103"); ++ return false; ++ } ++ ++ return true; ++} ++ ++void SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) { ++ if (mOutputPortSettingsChange != NONE || mEOSStatus == OUTPUT_FRAMES_FLUSHED) { ++ return; ++ } ++ ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ bool EOSseen = false; ++ bool portWillReset = false; ++ ++ while ((mEOSStatus == INPUT_EOS_SEEN || !inQueue.empty()) ++ && !outQueue.empty()) { ++ // Output the pending frames that left from last port reset or decoder flush. ++ if (mEOSStatus == INPUT_EOS_SEEN || mImg != NULL) { ++ if (!outputBuffers( ++ mEOSStatus == INPUT_EOS_SEEN, true /* display */, ++ mEOSStatus == INPUT_EOS_SEEN, &portWillReset)) { ++ ALOGE("on2 decoder failed to output frame."); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ if (portWillReset || mEOSStatus == OUTPUT_FRAMES_FLUSHED || ++ mEOSStatus == INPUT_EOS_SEEN) { ++ return; ++ } ++ // Continue as outQueue may be empty now. ++ continue; ++ } ++ ++ BufferInfo *inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++ ++ // Software VP9 Decoder does not need the Codec Specific Data (CSD) ++ // (specified in http://www.webmproject.org/vp9/profiles/). Ignore it if ++ // it was passed. ++ if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { ++ // Only ignore CSD buffer for VP9. ++ if (mMode == MODE_VP9) { ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ continue; ++ } else { ++ // Tolerate the CSD buffer for VP8. This is a workaround ++ // for b/28689536. ++ ALOGW("WARNING: Got CSD buffer for VP8."); ++ } ++ } ++ ++ mPrivInfo[mTimeStampIdx].mTimeStamp = inHeader->nTimeStamp; ++ ++ if (inInfo->mFrameConfig) { ++ mPrivInfo[mTimeStampIdx].mHdr10PlusInfo = dequeueInputFrameConfig(); ++ } else { ++ mPrivInfo[mTimeStampIdx].mHdr10PlusInfo.clear(); ++ } ++ ++ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ mEOSStatus = INPUT_EOS_SEEN; ++ EOSseen = true; ++ } ++ ++ if (inHeader->nFilledLen > 0) { ++ vpx_codec_err_t err = vpx_codec_decode( ++ (vpx_codec_ctx_t *)mCtx, inHeader->pBuffer + inHeader->nOffset, ++ inHeader->nFilledLen, &mPrivInfo[mTimeStampIdx], 0); ++ if (err == VPX_CODEC_OK) { ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ } else { ++ ALOGE("on2 decoder failed to decode frame. err: %d", err); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ } ++ ++ mTimeStampIdx = (mTimeStampIdx + 1) % kNumBuffers; ++ ++ if (!outputBuffers( ++ EOSseen /* flushDecoder */, true /* display */, EOSseen, &portWillReset)) { ++ ALOGE("on2 decoder failed to output frame."); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ if (portWillReset) { ++ return; ++ } ++ } ++} ++ ++void SoftVPX::onPortFlushCompleted(OMX_U32 portIndex) { ++ if (portIndex == kInputPortIndex) { ++ bool portWillReset = false; ++ if (!outputBuffers( ++ true /* flushDecoder */, false /* display */, false /* eos */, &portWillReset)) { ++ ALOGE("Failed to flush decoder."); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ mEOSStatus = INPUT_DATA_AVAILABLE; ++ } ++} ++ ++void SoftVPX::onReset() { ++ bool portWillReset = false; ++ if (!outputBuffers( ++ true /* flushDecoder */, false /* display */, false /* eos */, &portWillReset)) { ++ ALOGW("Failed to flush decoder. Try to hard reset decoder"); ++ destroyDecoder(); ++ initDecoder(); ++ } ++ mEOSStatus = INPUT_DATA_AVAILABLE; ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ if (!strcmp(name, "OMX.google.vp8.decoder")) { ++ return new android::SoftVPX( ++ name, "video_decoder.vp8", OMX_VIDEO_CodingVP8, ++ callbacks, appData, component); ++ } else if (!strcmp(name, "OMX.google.vp9.decoder")) { ++ return new android::SoftVPX( ++ name, "video_decoder.vp9", OMX_VIDEO_CodingVP9, ++ callbacks, appData, component); ++ } else { ++ CHECK(!"Unknown component"); ++ } ++ return NULL; ++} +diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.h b/media/libstagefright/codecs/on2/dec/SoftVPX.h +new file mode 100644 +index 0000000..0aa8e9c +--- /dev/null ++++ b/media/libstagefright/codecs/on2/dec/SoftVPX.h +@@ -0,0 +1,84 @@ ++/* ++ * Copyright (C) 2011 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 SOFT_VPX_H_ ++ ++#define SOFT_VPX_H_ ++ ++#include ++ ++#include "vpx/vpx_decoder.h" ++#include "vpx/vpx_codec.h" ++#include "vpx/vp8dx.h" ++ ++namespace android { ++ ++struct ABuffer; ++ ++struct SoftVPX : public SoftVideoDecoderOMXComponent { ++ SoftVPX(const char *name, ++ const char *componentRole, ++ OMX_VIDEO_CODINGTYPE codingType, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++protected: ++ virtual ~SoftVPX(); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ virtual void onPortFlushCompleted(OMX_U32 portIndex); ++ virtual void onReset(); ++ virtual bool supportDescribeHdrStaticInfo(); ++ virtual bool supportDescribeHdr10PlusInfo(); ++ ++private: ++ enum { ++ kNumBuffers = 10 ++ }; ++ ++ enum { ++ MODE_VP8, ++ MODE_VP9 ++ } mMode; ++ ++ enum { ++ INPUT_DATA_AVAILABLE, // VPX component is ready to decode data. ++ INPUT_EOS_SEEN, // VPX component saw EOS and is flushing On2 decoder. ++ OUTPUT_FRAMES_FLUSHED // VPX component finished flushing On2 decoder. ++ } mEOSStatus; ++ ++ void *mCtx; ++ bool mFrameParallelMode; // Frame parallel is only supported by VP9 decoder. ++ struct PrivInfo { ++ OMX_TICKS mTimeStamp; ++ sp mHdr10PlusInfo; ++ }; ++ PrivInfo mPrivInfo[kNumBuffers]; ++ uint8_t mTimeStampIdx; ++ vpx_image_t *mImg; ++ ++ status_t initDecoder(); ++ status_t destroyDecoder(); ++ bool outputBuffers(bool flushDecoder, bool display, bool eos, bool *portWillReset); ++ bool outputBufferSafe(OMX_BUFFERHEADERTYPE *outHeader); ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftVPX); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_VPX_H_ +diff --git a/media/libstagefright/codecs/on2/dec/exports.lds b/media/libstagefright/codecs/on2/dec/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/on2/dec/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/on2/enc/Android.bp b/media/libstagefright/codecs/on2/enc/Android.bp +new file mode 100644 +index 0000000..e85ff98 +--- /dev/null ++++ b/media/libstagefright/codecs/on2/enc/Android.bp +@@ -0,0 +1,44 @@ ++package { ++ default_applicable_licenses: [ ++ "frameworks_av_media_libstagefright_codecs_on2_enc_license", ++ ], ++} ++ ++// Added automatically by a large-scale-change ++// See: http://go/android-license-faq ++license { ++ name: "frameworks_av_media_libstagefright_codecs_on2_enc_license", ++ visibility: [":__subpackages__"], ++ license_kinds: [ ++ "SPDX-license-identifier-Apache-2.0", ++ ], ++ license_text: [ ++ "NOTICE", ++ ], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_vpxenc", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: [ ++ "SoftVPXEncoder.cpp", ++ "SoftVP8Encoder.cpp", ++ "SoftVP9Encoder.cpp", ++ ], ++ ++ cflags: ["-Wall"], ++ ++ version_script: "exports.lds", ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ "unsigned-integer-overflow", ++ ], ++ cfi: true, ++ }, ++ ++ shared_libs: ["libvpx"], ++ header_libs: ["libbase_headers"], ++} +diff --git a/media/libstagefright/codecs/on2/enc/MODULE_LICENSE_APACHE2 b/media/libstagefright/codecs/on2/enc/MODULE_LICENSE_APACHE2 +new file mode 100644 +index 0000000..e69de29 +diff --git a/media/libstagefright/codecs/on2/enc/NOTICE b/media/libstagefright/codecs/on2/enc/NOTICE +new file mode 100644 +index 0000000..faed58a +--- /dev/null ++++ b/media/libstagefright/codecs/on2/enc/NOTICE +@@ -0,0 +1,190 @@ ++ ++ Copyright (c) 2005-2013, 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. ++ ++ 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. ++ ++ ++ Apache License ++ Version 2.0, January 2004 ++ http://www.apache.org/licenses/ ++ ++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION ++ ++ 1. Definitions. ++ ++ "License" shall mean the terms and conditions for use, reproduction, ++ and distribution as defined by Sections 1 through 9 of this document. ++ ++ "Licensor" shall mean the copyright owner or entity authorized by ++ the copyright owner that is granting the License. ++ ++ "Legal Entity" shall mean the union of the acting entity and all ++ other entities that control, are controlled by, or are under common ++ control with that entity. For the purposes of this definition, ++ "control" means (i) the power, direct or indirect, to cause the ++ direction or management of such entity, whether by contract or ++ otherwise, or (ii) ownership of fifty percent (50%) or more of the ++ outstanding shares, or (iii) beneficial ownership of such entity. ++ ++ "You" (or "Your") shall mean an individual or Legal Entity ++ exercising permissions granted by this License. ++ ++ "Source" form shall mean the preferred form for making modifications, ++ including but not limited to software source code, documentation ++ source, and configuration files. ++ ++ "Object" form shall mean any form resulting from mechanical ++ transformation or translation of a Source form, including but ++ not limited to compiled object code, generated documentation, ++ and conversions to other media types. ++ ++ "Work" shall mean the work of authorship, whether in Source or ++ Object form, made available under the License, as indicated by a ++ copyright notice that is included in or attached to the work ++ (an example is provided in the Appendix below). ++ ++ "Derivative Works" shall mean any work, whether in Source or Object ++ form, that is based on (or derived from) the Work and for which the ++ editorial revisions, annotations, elaborations, or other modifications ++ represent, as a whole, an original work of authorship. For the purposes ++ of this License, Derivative Works shall not include works that remain ++ separable from, or merely link (or bind by name) to the interfaces of, ++ the Work and Derivative Works thereof. ++ ++ "Contribution" shall mean any work of authorship, including ++ the original version of the Work and any modifications or additions ++ to that Work or Derivative Works thereof, that is intentionally ++ submitted to Licensor for inclusion in the Work by the copyright owner ++ or by an individual or Legal Entity authorized to submit on behalf of ++ the copyright owner. For the purposes of this definition, "submitted" ++ means any form of electronic, verbal, or written communication sent ++ to the Licensor or its representatives, including but not limited to ++ communication on electronic mailing lists, source code control systems, ++ and issue tracking systems that are managed by, or on behalf of, the ++ Licensor for the purpose of discussing and improving the Work, but ++ excluding communication that is conspicuously marked or otherwise ++ designated in writing by the copyright owner as "Not a Contribution." ++ ++ "Contributor" shall mean Licensor and any individual or Legal Entity ++ on behalf of whom a Contribution has been received by Licensor and ++ subsequently incorporated within the Work. ++ ++ 2. Grant of Copyright License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ copyright license to reproduce, prepare Derivative Works of, ++ publicly display, publicly perform, sublicense, and distribute the ++ Work and such Derivative Works in Source or Object form. ++ ++ 3. Grant of Patent License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ (except as stated in this section) patent license to make, have made, ++ use, offer to sell, sell, import, and otherwise transfer the Work, ++ where such license applies only to those patent claims licensable ++ by such Contributor that are necessarily infringed by their ++ Contribution(s) alone or by combination of their Contribution(s) ++ with the Work to which such Contribution(s) was submitted. If You ++ institute patent litigation against any entity (including a ++ cross-claim or counterclaim in a lawsuit) alleging that the Work ++ or a Contribution incorporated within the Work constitutes direct ++ or contributory patent infringement, then any patent licenses ++ granted to You under this License for that Work shall terminate ++ as of the date such litigation is filed. ++ ++ 4. Redistribution. You may reproduce and distribute copies of the ++ Work or Derivative Works thereof in any medium, with or without ++ modifications, and in Source or Object form, provided that You ++ meet the following conditions: ++ ++ (a) You must give any other recipients of the Work or ++ Derivative Works a copy of this License; and ++ ++ (b) You must cause any modified files to carry prominent notices ++ stating that You changed the files; and ++ ++ (c) You must retain, in the Source form of any Derivative Works ++ that You distribute, all copyright, patent, trademark, and ++ attribution notices from the Source form of the Work, ++ excluding those notices that do not pertain to any part of ++ the Derivative Works; and ++ ++ (d) If the Work includes a "NOTICE" text file as part of its ++ distribution, then any Derivative Works that You distribute must ++ include a readable copy of the attribution notices contained ++ within such NOTICE file, excluding those notices that do not ++ pertain to any part of the Derivative Works, in at least one ++ of the following places: within a NOTICE text file distributed ++ as part of the Derivative Works; within the Source form or ++ documentation, if provided along with the Derivative Works; or, ++ within a display generated by the Derivative Works, if and ++ wherever such third-party notices normally appear. The contents ++ of the NOTICE file are for informational purposes only and ++ do not modify the License. You may add Your own attribution ++ notices within Derivative Works that You distribute, alongside ++ or as an addendum to the NOTICE text from the Work, provided ++ that such additional attribution notices cannot be construed ++ as modifying the License. ++ ++ You may add Your own copyright statement to Your modifications and ++ may provide additional or different license terms and conditions ++ for use, reproduction, or distribution of Your modifications, or ++ for any such Derivative Works as a whole, provided Your use, ++ reproduction, and distribution of the Work otherwise complies with ++ the conditions stated in this License. ++ ++ 5. Submission of Contributions. Unless You explicitly state otherwise, ++ any Contribution intentionally submitted for inclusion in the Work ++ by You to the Licensor shall be under the terms and conditions of ++ this License, without any additional terms or conditions. ++ Notwithstanding the above, nothing herein shall supersede or modify ++ the terms of any separate license agreement you may have executed ++ with Licensor regarding such Contributions. ++ ++ 6. Trademarks. This License does not grant permission to use the trade ++ names, trademarks, service marks, or product names of the Licensor, ++ except as required for reasonable and customary use in describing the ++ origin of the Work and reproducing the content of the NOTICE file. ++ ++ 7. Disclaimer of Warranty. Unless required by applicable law or ++ agreed to in writing, Licensor provides the Work (and each ++ Contributor provides its Contributions) on an "AS IS" BASIS, ++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or ++ implied, including, without limitation, any warranties or conditions ++ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A ++ PARTICULAR PURPOSE. You are solely responsible for determining the ++ appropriateness of using or redistributing the Work and assume any ++ risks associated with Your exercise of permissions under this License. ++ ++ 8. Limitation of Liability. In no event and under no legal theory, ++ whether in tort (including negligence), contract, or otherwise, ++ unless required by applicable law (such as deliberate and grossly ++ negligent acts) or agreed to in writing, shall any Contributor be ++ liable to You for damages, including any direct, indirect, special, ++ incidental, or consequential damages of any character arising as a ++ result of this License or out of the use or inability to use the ++ Work (including but not limited to damages for loss of goodwill, ++ work stoppage, computer failure or malfunction, or any and all ++ other commercial damages or losses), even if such Contributor ++ has been advised of the possibility of such damages. ++ ++ 9. Accepting Warranty or Additional Liability. While redistributing ++ the Work or Derivative Works thereof, You may choose to offer, ++ and charge a fee for, acceptance of support, warranty, indemnity, ++ or other liability obligations and/or rights consistent with this ++ License. However, in accepting such obligations, You may act only ++ on Your own behalf and on Your sole responsibility, not on behalf ++ of any other Contributor, and only if You agree to indemnify, ++ defend, and hold each Contributor harmless for any liability ++ incurred by, or claims asserted against, such Contributor by reason ++ of your accepting any such warranty or additional liability. ++ ++ END OF TERMS AND CONDITIONS ++ +diff --git a/media/libstagefright/codecs/on2/enc/SoftVP8Encoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVP8Encoder.cpp +new file mode 100644 +index 0000000..9198b7c +--- /dev/null ++++ b/media/libstagefright/codecs/on2/enc/SoftVP8Encoder.cpp +@@ -0,0 +1,172 @@ ++/* ++ * Copyright (C) 2016 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 "SoftVP8Encoder" ++#include "SoftVP8Encoder.h" ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#ifndef INT32_MAX ++#define INT32_MAX 2147483647 ++#endif ++ ++namespace android { ++ ++static const CodecProfileLevel kVp8ProfileLevels[] = { ++ { OMX_VIDEO_VP8ProfileMain, OMX_VIDEO_VP8Level_Version0 }, ++ { OMX_VIDEO_VP8ProfileMain, OMX_VIDEO_VP8Level_Version1 }, ++ { OMX_VIDEO_VP8ProfileMain, OMX_VIDEO_VP8Level_Version2 }, ++ { OMX_VIDEO_VP8ProfileMain, OMX_VIDEO_VP8Level_Version3 }, ++}; ++ ++SoftVP8Encoder::SoftVP8Encoder(const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SoftVPXEncoder( ++ name, callbacks, appData, component, "video_encoder.vp8", ++ OMX_VIDEO_CodingVP8, MEDIA_MIMETYPE_VIDEO_VP8, 2, ++ kVp8ProfileLevels, NELEM(kVp8ProfileLevels)), ++ mDCTPartitions(0), ++ mLevel(OMX_VIDEO_VP8Level_Version0) { ++} ++ ++void SoftVP8Encoder::setCodecSpecificInterface() { ++ mCodecInterface = vpx_codec_vp8_cx(); ++} ++ ++void SoftVP8Encoder::setCodecSpecificConfiguration() { ++ switch (mLevel) { ++ case OMX_VIDEO_VP8Level_Version0: ++ mCodecConfiguration->g_profile = 0; ++ break; ++ ++ case OMX_VIDEO_VP8Level_Version1: ++ mCodecConfiguration->g_profile = 1; ++ break; ++ ++ case OMX_VIDEO_VP8Level_Version2: ++ mCodecConfiguration->g_profile = 2; ++ break; ++ ++ case OMX_VIDEO_VP8Level_Version3: ++ mCodecConfiguration->g_profile = 3; ++ break; ++ ++ default: ++ mCodecConfiguration->g_profile = 0; ++ } ++} ++ ++vpx_codec_err_t SoftVP8Encoder::setCodecSpecificControls() { ++ vpx_codec_err_t codec_return = vpx_codec_control(mCodecContext, ++ VP8E_SET_TOKEN_PARTITIONS, ++ mDCTPartitions); ++ if (codec_return != VPX_CODEC_OK) { ++ ALOGE("Error setting dct partitions for vpx encoder."); ++ } ++ return codec_return; ++} ++ ++OMX_ERRORTYPE SoftVP8Encoder::internalGetParameter(OMX_INDEXTYPE index, ++ OMX_PTR param) { ++ // can include extension index OMX_INDEXEXTTYPE ++ const int32_t indexFull = index; ++ ++ switch (indexFull) { ++ case OMX_IndexParamVideoVp8: ++ return internalGetVp8Params( ++ (OMX_VIDEO_PARAM_VP8TYPE *)param); ++ ++ default: ++ return SoftVPXEncoder::internalGetParameter(index, param); ++ } ++} ++ ++OMX_ERRORTYPE SoftVP8Encoder::internalSetParameter(OMX_INDEXTYPE index, ++ const OMX_PTR param) { ++ // can include extension index OMX_INDEXEXTTYPE ++ const int32_t indexFull = index; ++ ++ switch (indexFull) { ++ case OMX_IndexParamVideoVp8: ++ return internalSetVp8Params( ++ (const OMX_VIDEO_PARAM_VP8TYPE *)param); ++ ++ default: ++ return SoftVPXEncoder::internalSetParameter(index, param); ++ } ++} ++ ++OMX_ERRORTYPE SoftVP8Encoder::internalGetVp8Params( ++ OMX_VIDEO_PARAM_VP8TYPE* vp8Params) { ++ if (!isValidOMXParam(vp8Params)) { ++ android_errorWriteLog(0x534e4554, "273936274"); ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (vp8Params->nPortIndex != kOutputPortIndex) { ++ return OMX_ErrorUnsupportedIndex; ++ } ++ ++ vp8Params->eProfile = OMX_VIDEO_VP8ProfileMain; ++ vp8Params->eLevel = mLevel; ++ vp8Params->bErrorResilientMode = mErrorResilience; ++ vp8Params->nDCTPartitions = mDCTPartitions; ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftVP8Encoder::internalSetVp8Params( ++ const OMX_VIDEO_PARAM_VP8TYPE* vp8Params) { ++ if (!isValidOMXParam(vp8Params)) { ++ android_errorWriteLog(0x534e4554, "273937171"); ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (vp8Params->nPortIndex != kOutputPortIndex) { ++ return OMX_ErrorUnsupportedIndex; ++ } ++ ++ if (vp8Params->eProfile != OMX_VIDEO_VP8ProfileMain) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (vp8Params->eLevel == OMX_VIDEO_VP8Level_Version0 || ++ vp8Params->eLevel == OMX_VIDEO_VP8Level_Version1 || ++ vp8Params->eLevel == OMX_VIDEO_VP8Level_Version2 || ++ vp8Params->eLevel == OMX_VIDEO_VP8Level_Version3) { ++ mLevel = vp8Params->eLevel; ++ } else { ++ return OMX_ErrorBadParameter; ++ } ++ ++ mErrorResilience = vp8Params->bErrorResilientMode; ++ if (vp8Params->nDCTPartitions <= kMaxDCTPartitions) { ++ mDCTPartitions = vp8Params->nDCTPartitions; ++ } else { ++ return OMX_ErrorBadParameter; ++ } ++ return OMX_ErrorNone; ++} ++ ++} // namespace android +diff --git a/media/libstagefright/codecs/on2/enc/SoftVP8Encoder.h b/media/libstagefright/codecs/on2/enc/SoftVP8Encoder.h +new file mode 100644 +index 0000000..c5c2abf +--- /dev/null ++++ b/media/libstagefright/codecs/on2/enc/SoftVP8Encoder.h +@@ -0,0 +1,93 @@ ++/* ++ * Copyright (C) 2016 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 SOFT_VP8_ENCODER_H_ ++ ++#define SOFT_VP8_ENCODER_H_ ++ ++#include "SoftVPXEncoder.h" ++ ++#include ++#include ++ ++#include "vpx/vpx_encoder.h" ++#include "vpx/vpx_codec.h" ++#include "vpx/vp8cx.h" ++ ++namespace android { ++ ++// Exposes a vp8 encoder as an OMX Component ++// ++// In addition to the base class settings, Only following encoder settings are ++// available: ++// - token partitioning ++struct SoftVP8Encoder : public SoftVPXEncoder { ++ SoftVP8Encoder(const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++protected: ++ // Returns current values for requested OMX ++ // parameters ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR param); ++ ++ // Validates, extracts and stores relevant OMX ++ // parameters ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR param); ++ ++ // Populates |mCodecInterface| with codec specific settings. ++ virtual void setCodecSpecificInterface(); ++ ++ // Sets codec specific configuration. ++ virtual void setCodecSpecificConfiguration(); ++ ++ // Initializes codec specific encoder settings. ++ virtual vpx_codec_err_t setCodecSpecificControls(); ++ ++ // Gets vp8 specific parameters. ++ OMX_ERRORTYPE internalGetVp8Params( ++ OMX_VIDEO_PARAM_VP8TYPE* vp8Params); ++ ++ // Handles vp8 specific parameters. ++ OMX_ERRORTYPE internalSetVp8Params( ++ const OMX_VIDEO_PARAM_VP8TYPE* vp8Params); ++ ++private: ++ // Max value supported for DCT partitions ++ static const uint32_t kMaxDCTPartitions = 3; ++ ++ // vp8 specific configuration parameter ++ // that enables token partitioning of ++ // the stream into substreams ++ int32_t mDCTPartitions; ++ ++ // Encoder profile corresponding to OMX level parameter ++ // ++ // The inconsistency in the naming is caused by ++ // OMX spec referring vpx profiles (g_profile) ++ // as "levels" whereas using the name "profile" for ++ // something else. ++ OMX_VIDEO_VP8LEVELTYPE mLevel; ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftVP8Encoder); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_VP8_ENCODER_H_ +diff --git a/media/libstagefright/codecs/on2/enc/SoftVP9Encoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVP9Encoder.cpp +new file mode 100644 +index 0000000..f8495c2 +--- /dev/null ++++ b/media/libstagefright/codecs/on2/enc/SoftVP9Encoder.cpp +@@ -0,0 +1,179 @@ ++/* ++ * Copyright (C) 2016 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 "SoftVP9Encoder" ++#include "SoftVP9Encoder.h" ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++namespace android { ++ ++static const CodecProfileLevel kVp9ProfileLevels[] = { ++ { OMX_VIDEO_VP9Profile0, OMX_VIDEO_VP9Level41 }, ++}; ++ ++SoftVP9Encoder::SoftVP9Encoder( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SoftVPXEncoder( ++ name, callbacks, appData, component, "video_encoder.vp9", ++ OMX_VIDEO_CodingVP9, MEDIA_MIMETYPE_VIDEO_VP9, 4, ++ kVp9ProfileLevels, NELEM(kVp9ProfileLevels)), ++ mLevel(OMX_VIDEO_VP9Level1), ++ mTileColumns(0), ++ mFrameParallelDecoding(OMX_FALSE) { ++} ++ ++void SoftVP9Encoder::setCodecSpecificInterface() { ++ mCodecInterface = vpx_codec_vp9_cx(); ++} ++ ++void SoftVP9Encoder::setCodecSpecificConfiguration() { ++ mCodecConfiguration->g_profile = 0; ++} ++ ++vpx_codec_err_t SoftVP9Encoder::setCodecSpecificControls() { ++ vpx_codec_err_t codecReturn = vpx_codec_control( ++ mCodecContext, VP9E_SET_TILE_COLUMNS, mTileColumns); ++ if (codecReturn != VPX_CODEC_OK) { ++ ALOGE("Error setting VP9E_SET_TILE_COLUMNS to %d. vpx_codec_control() " ++ "returned %d", mTileColumns, codecReturn); ++ return codecReturn; ++ } ++ codecReturn = vpx_codec_control( ++ mCodecContext, VP9E_SET_FRAME_PARALLEL_DECODING, ++ mFrameParallelDecoding); ++ if (codecReturn != VPX_CODEC_OK) { ++ ALOGE("Error setting VP9E_SET_FRAME_PARALLEL_DECODING to %d." ++ "vpx_codec_control() returned %d", mFrameParallelDecoding, ++ codecReturn); ++ return codecReturn; ++ } ++ codecReturn = vpx_codec_control(mCodecContext, VP9E_SET_ROW_MT, 1); ++ if (codecReturn != VPX_CODEC_OK) { ++ ALOGE("Error setting VP9E_SET_ROW_MT to 1. vpx_codec_control() " ++ "returned %d", codecReturn); ++ return codecReturn; ++ } ++ ++ // For VP9, we always set CPU_USED to 8 (because the realtime default is 0 ++ // which is too slow). ++ codecReturn = vpx_codec_control(mCodecContext, VP8E_SET_CPUUSED, 8); ++ if (codecReturn != VPX_CODEC_OK) { ++ ALOGE("Error setting VP8E_SET_CPUUSED to 8. vpx_codec_control() " ++ "returned %d", codecReturn); ++ return codecReturn; ++ } ++ return codecReturn; ++} ++ ++OMX_ERRORTYPE SoftVP9Encoder::internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR param) { ++ // can include extension index OMX_INDEXEXTTYPE ++ const int32_t indexFull = index; ++ ++ switch (indexFull) { ++ case OMX_IndexParamVideoVp9: ++ return internalGetVp9Params( ++ (OMX_VIDEO_PARAM_VP9TYPE *)param); ++ ++ default: ++ return SoftVPXEncoder::internalGetParameter(index, param); ++ } ++} ++ ++OMX_ERRORTYPE SoftVP9Encoder::internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR param) { ++ // can include extension index OMX_INDEXEXTTYPE ++ const int32_t indexFull = index; ++ ++ switch (indexFull) { ++ case OMX_IndexParamVideoVp9: ++ return internalSetVp9Params( ++ (const OMX_VIDEO_PARAM_VP9TYPE *)param); ++ ++ default: ++ return SoftVPXEncoder::internalSetParameter(index, param); ++ } ++} ++ ++OMX_ERRORTYPE SoftVP9Encoder::internalGetVp9Params( ++ OMX_VIDEO_PARAM_VP9TYPE *vp9Params) { ++ if (!isValidOMXParam(vp9Params)) { ++ android_errorWriteLog(0x534e4554, "273936553"); ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (vp9Params->nPortIndex != kOutputPortIndex) { ++ return OMX_ErrorUnsupportedIndex; ++ } ++ ++ vp9Params->eProfile = OMX_VIDEO_VP9Profile0; ++ vp9Params->eLevel = mLevel; ++ vp9Params->bErrorResilientMode = mErrorResilience; ++ vp9Params->nTileColumns = mTileColumns; ++ vp9Params->bEnableFrameParallelDecoding = mFrameParallelDecoding; ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftVP9Encoder::internalSetVp9Params( ++ const OMX_VIDEO_PARAM_VP9TYPE *vp9Params) { ++ if (!isValidOMXParam(vp9Params)) { ++ android_errorWriteLog(0x534e4554, "273937136"); ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (vp9Params->nPortIndex != kOutputPortIndex) { ++ return OMX_ErrorUnsupportedIndex; ++ } ++ ++ if (vp9Params->eProfile != OMX_VIDEO_VP9Profile0) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (vp9Params->eLevel == OMX_VIDEO_VP9Level1 || ++ vp9Params->eLevel == OMX_VIDEO_VP9Level11 || ++ vp9Params->eLevel == OMX_VIDEO_VP9Level2 || ++ vp9Params->eLevel == OMX_VIDEO_VP9Level21 || ++ vp9Params->eLevel == OMX_VIDEO_VP9Level3 || ++ vp9Params->eLevel == OMX_VIDEO_VP9Level31 || ++ vp9Params->eLevel == OMX_VIDEO_VP9Level4 || ++ vp9Params->eLevel == OMX_VIDEO_VP9Level41 || ++ vp9Params->eLevel == OMX_VIDEO_VP9Level5 || ++ vp9Params->eLevel == OMX_VIDEO_VP9Level51 || ++ vp9Params->eLevel == OMX_VIDEO_VP9Level52 || ++ vp9Params->eLevel == OMX_VIDEO_VP9Level6 || ++ vp9Params->eLevel == OMX_VIDEO_VP9Level61 || ++ vp9Params->eLevel == OMX_VIDEO_VP9Level62) { ++ mLevel = vp9Params->eLevel; ++ } else { ++ return OMX_ErrorBadParameter; ++ } ++ ++ mErrorResilience = vp9Params->bErrorResilientMode; ++ mTileColumns = vp9Params->nTileColumns; ++ mFrameParallelDecoding = vp9Params->bEnableFrameParallelDecoding; ++ return OMX_ErrorNone; ++} ++ ++} // namespace android +diff --git a/media/libstagefright/codecs/on2/enc/SoftVP9Encoder.h b/media/libstagefright/codecs/on2/enc/SoftVP9Encoder.h +new file mode 100644 +index 0000000..308a9ac +--- /dev/null ++++ b/media/libstagefright/codecs/on2/enc/SoftVP9Encoder.h +@@ -0,0 +1,91 @@ ++/* ++ * Copyright (C) 2016 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 SOFT_VP9_ENCODER_H_ ++ ++#define SOFT_VP9_ENCODER_H_ ++ ++#include "SoftVPXEncoder.h" ++ ++#include ++#include ++ ++#include "vpx/vpx_encoder.h" ++#include "vpx/vpx_codec.h" ++#include "vpx/vp8cx.h" ++ ++namespace android { ++ ++// Exposes a VP9 encoder as an OMX Component ++// ++// In addition to the base class settings, Only following encoder settings are ++// available: ++// - tile rows ++// - tile columns ++// - frame parallel mode ++struct SoftVP9Encoder : public SoftVPXEncoder { ++ SoftVP9Encoder(const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++protected: ++ // Returns current values for requested OMX ++ // parameters ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR param); ++ ++ // Validates, extracts and stores relevant OMX ++ // parameters ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR param); ++ ++ // Populates |mCodecInterface| with codec specific settings. ++ virtual void setCodecSpecificInterface(); ++ ++ // Sets codec specific configuration. ++ virtual void setCodecSpecificConfiguration(); ++ ++ // Initializes codec specific encoder settings. ++ virtual vpx_codec_err_t setCodecSpecificControls(); ++ ++ // Gets vp9 specific parameters. ++ OMX_ERRORTYPE internalGetVp9Params( ++ OMX_VIDEO_PARAM_VP9TYPE* vp9Params); ++ ++ // Handles vp9 specific parameters. ++ OMX_ERRORTYPE internalSetVp9Params( ++ const OMX_VIDEO_PARAM_VP9TYPE* vp9Params); ++ ++private: ++ // Encoder profile corresponding to OMX level parameter ++ // ++ // The inconsistency in the naming is caused by ++ // OMX spec referring vpx profiles (g_profile) ++ // as "levels" whereas using the name "profile" for ++ // something else. ++ OMX_VIDEO_VP9LEVELTYPE mLevel; ++ ++ int32_t mTileColumns; ++ ++ OMX_BOOL mFrameParallelDecoding; ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftVP9Encoder); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_VP9_ENCODER_H_ +diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp +new file mode 100644 +index 0000000..cbedb72 +--- /dev/null ++++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp +@@ -0,0 +1,799 @@ ++/* ++ * Copyright (C) 2013 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 "SoftVPXEncoder" ++#include "SoftVPXEncoder.h" ++ ++#include "SoftVP8Encoder.h" ++#include "SoftVP9Encoder.h" ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#ifndef INT32_MAX ++#define INT32_MAX 2147483647 ++#endif ++ ++namespace android { ++ ++template ++static void InitOMXParams(T *params) { ++ params->nSize = sizeof(T); ++ // OMX IL 1.1.2 ++ params->nVersion.s.nVersionMajor = 1; ++ params->nVersion.s.nVersionMinor = 1; ++ params->nVersion.s.nRevision = 2; ++ params->nVersion.s.nStep = 0; ++} ++ ++static int GetCPUCoreCount() { ++ int cpuCoreCount = 1; ++#if defined(_SC_NPROCESSORS_ONLN) ++ cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); ++#else ++ // _SC_NPROC_ONLN must be defined... ++ cpuCoreCount = sysconf(_SC_NPROC_ONLN); ++#endif ++ CHECK_GE(cpuCoreCount, 1); ++ return cpuCoreCount; ++} ++ ++SoftVPXEncoder::SoftVPXEncoder(const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component, ++ const char* role, ++ OMX_VIDEO_CODINGTYPE codingType, ++ const char* mimeType, ++ int32_t minCompressionRatio, ++ const CodecProfileLevel *profileLevels, ++ size_t numProfileLevels) ++ : SoftVideoEncoderOMXComponent( ++ name, role, codingType, profileLevels, numProfileLevels, ++ 176 /* width */, 144 /* height */, ++ callbacks, appData, component), ++ mCodecContext(NULL), ++ mCodecConfiguration(NULL), ++ mCodecInterface(NULL), ++ mBitrateUpdated(false), ++ mBitrateControlMode(VPX_VBR), ++ mErrorResilience(OMX_FALSE), ++ mKeyFrameInterval(0), ++ mMinQuantizer(0), ++ mMaxQuantizer(0), ++ mTemporalLayers(0), ++ mTemporalPatternType(OMX_VIDEO_VPXTemporalLayerPatternNone), ++ mTemporalPatternLength(0), ++ mTemporalPatternIdx(0), ++ mLastTimestamp(0x7FFFFFFFFFFFFFFFLL), ++ mConversionBuffer(NULL), ++ mKeyFrameRequested(false) { ++ memset(mTemporalLayerBitrateRatio, 0, sizeof(mTemporalLayerBitrateRatio)); ++ mTemporalLayerBitrateRatio[0] = 100; ++ ++ const size_t kMinOutputBufferSize = 1024 * 1024; // arbitrary ++ ++ initPorts( ++ kNumBuffers, kNumBuffers, kMinOutputBufferSize, ++ mimeType, minCompressionRatio); ++} ++ ++SoftVPXEncoder::~SoftVPXEncoder() { ++ releaseEncoder(); ++} ++ ++status_t SoftVPXEncoder::initEncoder() { ++ vpx_codec_err_t codec_return; ++ status_t result = UNKNOWN_ERROR; ++ ++ setCodecSpecificInterface(); ++ if (mCodecInterface == NULL) { ++ goto CLEAN_UP; ++ } ++ ALOGD("VPx: initEncoder. BRMode: %u. TSLayers: %zu. KF: %u. QP: %u - %u", ++ (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval, ++ mMinQuantizer, mMaxQuantizer); ++ ++ mCodecConfiguration = new vpx_codec_enc_cfg_t; ++ codec_return = vpx_codec_enc_config_default(mCodecInterface, ++ mCodecConfiguration, ++ 0); ++ ++ if (codec_return != VPX_CODEC_OK) { ++ ALOGE("Error populating default configuration for vpx encoder."); ++ goto CLEAN_UP; ++ } ++ ++ mCodecConfiguration->g_w = mWidth; ++ mCodecConfiguration->g_h = mHeight; ++ mCodecConfiguration->g_threads = GetCPUCoreCount(); ++ mCodecConfiguration->g_error_resilient = mErrorResilience; ++ ++ // OMX timebase unit is microsecond ++ // g_timebase is in seconds (i.e. 1/1000000 seconds) ++ mCodecConfiguration->g_timebase.num = 1; ++ mCodecConfiguration->g_timebase.den = 1000000; ++ // rc_target_bitrate is in kbps, mBitrate in bps ++ mCodecConfiguration->rc_target_bitrate = (mBitrate + 500) / 1000; ++ mCodecConfiguration->rc_end_usage = mBitrateControlMode; ++ // Disable frame drop - not allowed in MediaCodec now. ++ mCodecConfiguration->rc_dropframe_thresh = 0; ++ // Disable lagged encoding. ++ mCodecConfiguration->g_lag_in_frames = 0; ++ if (mBitrateControlMode == VPX_CBR) { ++ // Disable spatial resizing. ++ mCodecConfiguration->rc_resize_allowed = 0; ++ // Single-pass mode. ++ mCodecConfiguration->g_pass = VPX_RC_ONE_PASS; ++ // Maximum amount of bits that can be subtracted from the target ++ // bitrate - expressed as percentage of the target bitrate. ++ mCodecConfiguration->rc_undershoot_pct = 100; ++ // Maximum amount of bits that can be added to the target ++ // bitrate - expressed as percentage of the target bitrate. ++ mCodecConfiguration->rc_overshoot_pct = 15; ++ // Initial value of the buffer level in ms. ++ mCodecConfiguration->rc_buf_initial_sz = 500; ++ // Amount of data that the encoder should try to maintain in ms. ++ mCodecConfiguration->rc_buf_optimal_sz = 600; ++ // The amount of data that may be buffered by the decoding ++ // application in ms. ++ mCodecConfiguration->rc_buf_sz = 1000; ++ // Enable error resilience - needed for packet loss. ++ mCodecConfiguration->g_error_resilient = 1; ++ // Maximum key frame interval - for CBR boost to 3000 ++ mCodecConfiguration->kf_max_dist = 3000; ++ // Encoder determines optimal key frame placement automatically. ++ mCodecConfiguration->kf_mode = VPX_KF_AUTO; ++ } ++ ++ // Frames temporal pattern - for now WebRTC like pattern is only supported. ++ switch (mTemporalLayers) { ++ case 0: ++ { ++ mTemporalPatternLength = 0; ++ break; ++ } ++ case 1: ++ { ++ mCodecConfiguration->ts_number_layers = 1; ++ mCodecConfiguration->ts_rate_decimator[0] = 1; ++ mCodecConfiguration->ts_periodicity = 1; ++ mCodecConfiguration->ts_layer_id[0] = 0; ++ mTemporalPattern[0] = kTemporalUpdateLastRefAll; ++ mTemporalPatternLength = 1; ++ break; ++ } ++ case 2: ++ { ++ mCodecConfiguration->ts_number_layers = 2; ++ mCodecConfiguration->ts_rate_decimator[0] = 2; ++ mCodecConfiguration->ts_rate_decimator[1] = 1; ++ mCodecConfiguration->ts_periodicity = 2; ++ mCodecConfiguration->ts_layer_id[0] = 0; ++ mCodecConfiguration->ts_layer_id[1] = 1; ++ mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef; ++ mTemporalPattern[1] = kTemporalUpdateGoldenWithoutDependencyRefAltRef; ++ mTemporalPattern[2] = kTemporalUpdateLastRefAltRef; ++ mTemporalPattern[3] = kTemporalUpdateGoldenRefAltRef; ++ mTemporalPattern[4] = kTemporalUpdateLastRefAltRef; ++ mTemporalPattern[5] = kTemporalUpdateGoldenRefAltRef; ++ mTemporalPattern[6] = kTemporalUpdateLastRefAltRef; ++ mTemporalPattern[7] = kTemporalUpdateNone; ++ mTemporalPatternLength = 8; ++ break; ++ } ++ case 3: ++ { ++ mCodecConfiguration->ts_number_layers = 3; ++ mCodecConfiguration->ts_rate_decimator[0] = 4; ++ mCodecConfiguration->ts_rate_decimator[1] = 2; ++ mCodecConfiguration->ts_rate_decimator[2] = 1; ++ mCodecConfiguration->ts_periodicity = 4; ++ mCodecConfiguration->ts_layer_id[0] = 0; ++ mCodecConfiguration->ts_layer_id[1] = 2; ++ mCodecConfiguration->ts_layer_id[2] = 1; ++ mCodecConfiguration->ts_layer_id[3] = 2; ++ mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef; ++ mTemporalPattern[1] = kTemporalUpdateNoneNoRefGoldenRefAltRef; ++ mTemporalPattern[2] = kTemporalUpdateGoldenWithoutDependencyRefAltRef; ++ mTemporalPattern[3] = kTemporalUpdateNone; ++ mTemporalPattern[4] = kTemporalUpdateLastRefAltRef; ++ mTemporalPattern[5] = kTemporalUpdateNone; ++ mTemporalPattern[6] = kTemporalUpdateGoldenRefAltRef; ++ mTemporalPattern[7] = kTemporalUpdateNone; ++ mTemporalPatternLength = 8; ++ break; ++ } ++ default: ++ { ++ ALOGE("Wrong number of temporal layers %zu", mTemporalLayers); ++ goto CLEAN_UP; ++ } ++ } ++ // Set bitrate values for each layer ++ for (size_t i = 0; i < mCodecConfiguration->ts_number_layers; i++) { ++ mCodecConfiguration->ts_target_bitrate[i] = ++ mCodecConfiguration->rc_target_bitrate * ++ mTemporalLayerBitrateRatio[i] / 100; ++ } ++ if (mKeyFrameInterval > 0) { ++ mCodecConfiguration->kf_max_dist = mKeyFrameInterval; ++ mCodecConfiguration->kf_min_dist = mKeyFrameInterval; ++ mCodecConfiguration->kf_mode = VPX_KF_AUTO; ++ } ++ if (mMinQuantizer > 0) { ++ mCodecConfiguration->rc_min_quantizer = mMinQuantizer; ++ } ++ if (mMaxQuantizer > 0) { ++ mCodecConfiguration->rc_max_quantizer = mMaxQuantizer; ++ } ++ setCodecSpecificConfiguration(); ++ mCodecContext = new vpx_codec_ctx_t; ++ codec_return = vpx_codec_enc_init(mCodecContext, ++ mCodecInterface, ++ mCodecConfiguration, ++ 0); // flags ++ ++ if (codec_return != VPX_CODEC_OK) { ++ ALOGE("Error initializing vpx encoder"); ++ goto CLEAN_UP; ++ } ++ ++ // Extra CBR settings ++ if (mBitrateControlMode == VPX_CBR) { ++ codec_return = vpx_codec_control(mCodecContext, ++ VP8E_SET_STATIC_THRESHOLD, ++ 1); ++ if (codec_return == VPX_CODEC_OK) { ++ uint32_t rc_max_intra_target = ++ mCodecConfiguration->rc_buf_optimal_sz * (mFramerate >> 17) / 10; ++ // Don't go below 3 times per frame bandwidth. ++ if (rc_max_intra_target < 300) { ++ rc_max_intra_target = 300; ++ } ++ codec_return = vpx_codec_control(mCodecContext, ++ VP8E_SET_MAX_INTRA_BITRATE_PCT, ++ rc_max_intra_target); ++ } ++ if (codec_return == VPX_CODEC_OK) { ++ codec_return = vpx_codec_control(mCodecContext, ++ VP8E_SET_CPUUSED, ++ -8); ++ } ++ if (codec_return != VPX_CODEC_OK) { ++ ALOGE("Error setting cbr parameters for vpx encoder."); ++ goto CLEAN_UP; ++ } ++ } ++ ++ codec_return = setCodecSpecificControls(); ++ ++ if (codec_return != VPX_CODEC_OK) { ++ // The codec specific method would have logged the error. ++ goto CLEAN_UP; ++ } ++ ++ if (mColorFormat != OMX_COLOR_FormatYUV420Planar || mInputDataIsMeta) { ++ free(mConversionBuffer); ++ mConversionBuffer = NULL; ++ if (((uint64_t)mWidth * mHeight) > ((uint64_t)INT32_MAX / 3)) { ++ ALOGE("b/25812794, Buffer size is too big, width=%d, height=%d.", mWidth, mHeight); ++ goto CLEAN_UP; ++ } ++ mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2); ++ if (mConversionBuffer == NULL) { ++ ALOGE("Allocating conversion buffer failed."); ++ goto CLEAN_UP; ++ } ++ } ++ return OK; ++ ++CLEAN_UP: ++ releaseEncoder(); ++ return result; ++} ++ ++status_t SoftVPXEncoder::releaseEncoder() { ++ if (mCodecContext != NULL) { ++ vpx_codec_destroy(mCodecContext); ++ delete mCodecContext; ++ mCodecContext = NULL; ++ } ++ ++ if (mCodecConfiguration != NULL) { ++ delete mCodecConfiguration; ++ mCodecConfiguration = NULL; ++ } ++ ++ if (mConversionBuffer != NULL) { ++ free(mConversionBuffer); ++ mConversionBuffer = NULL; ++ } ++ ++ // this one is not allocated by us ++ mCodecInterface = NULL; ++ ++ return OK; ++} ++ ++OMX_ERRORTYPE SoftVPXEncoder::internalGetParameter(OMX_INDEXTYPE index, ++ OMX_PTR param) { ++ // can include extension index OMX_INDEXEXTTYPE ++ const int32_t indexFull = index; ++ ++ switch (indexFull) { ++ case OMX_IndexParamVideoBitrate: { ++ OMX_VIDEO_PARAM_BITRATETYPE *bitrate = ++ (OMX_VIDEO_PARAM_BITRATETYPE *)param; ++ ++ if (!isValidOMXParam(bitrate)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (bitrate->nPortIndex != kOutputPortIndex) { ++ return OMX_ErrorUnsupportedIndex; ++ } ++ ++ bitrate->nTargetBitrate = mBitrate; ++ ++ if (mBitrateControlMode == VPX_VBR) { ++ bitrate->eControlRate = OMX_Video_ControlRateVariable; ++ } else if (mBitrateControlMode == VPX_CBR) { ++ bitrate->eControlRate = OMX_Video_ControlRateConstant; ++ } else { ++ return OMX_ErrorUnsupportedSetting; ++ } ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamVideoAndroidVp8Encoder: ++ return internalGetAndroidVpxParams( ++ (OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param); ++ ++ default: ++ return SoftVideoEncoderOMXComponent::internalGetParameter(index, param); ++ } ++} ++ ++OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index, ++ const OMX_PTR param) { ++ // can include extension index OMX_INDEXEXTTYPE ++ const int32_t indexFull = index; ++ ++ switch (indexFull) { ++ case OMX_IndexParamVideoBitrate: { ++ const OMX_VIDEO_PARAM_BITRATETYPE *bitRate = ++ (const OMX_VIDEO_PARAM_BITRATETYPE*) param; ++ ++ if (!isValidOMXParam(bitRate)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ return internalSetBitrateParams(bitRate); ++ } ++ ++ case OMX_IndexParamVideoAndroidVp8Encoder: ++ return internalSetAndroidVpxParams( ++ (const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param); ++ ++ default: ++ return SoftVideoEncoderOMXComponent::internalSetParameter(index, param); ++ } ++} ++ ++OMX_ERRORTYPE SoftVPXEncoder::internalSetConfig( ++ OMX_INDEXTYPE index, const OMX_PTR _params, bool *frameConfig) { ++ switch (index) { ++ case OMX_IndexConfigVideoIntraVOPRefresh: ++ { ++ OMX_CONFIG_INTRAREFRESHVOPTYPE *params = ++ (OMX_CONFIG_INTRAREFRESHVOPTYPE *)_params; ++ ++ if (!isValidOMXParam(params)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (params->nPortIndex != kOutputPortIndex) { ++ return OMX_ErrorBadPortIndex; ++ } ++ ++ mKeyFrameRequested = params->IntraRefreshVOP; ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexConfigVideoBitrate: ++ { ++ OMX_VIDEO_CONFIG_BITRATETYPE *params = ++ (OMX_VIDEO_CONFIG_BITRATETYPE *)_params; ++ ++ if (!isValidOMXParam(params)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (params->nPortIndex != kOutputPortIndex) { ++ return OMX_ErrorBadPortIndex; ++ } ++ ++ if (mBitrate != params->nEncodeBitrate) { ++ mBitrate = params->nEncodeBitrate; ++ mBitrateUpdated = true; ++ } ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalSetConfig(index, _params, frameConfig); ++ } ++} ++ ++OMX_ERRORTYPE SoftVPXEncoder::internalGetBitrateParams( ++ OMX_VIDEO_PARAM_BITRATETYPE* bitrate) { ++ if (bitrate->nPortIndex != kOutputPortIndex) { ++ return OMX_ErrorUnsupportedIndex; ++ } ++ ++ bitrate->nTargetBitrate = mBitrate; ++ ++ if (mBitrateControlMode == VPX_VBR) { ++ bitrate->eControlRate = OMX_Video_ControlRateVariable; ++ } else if (mBitrateControlMode == VPX_CBR) { ++ bitrate->eControlRate = OMX_Video_ControlRateConstant; ++ } else { ++ return OMX_ErrorUnsupportedSetting; ++ } ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftVPXEncoder::internalSetBitrateParams( ++ const OMX_VIDEO_PARAM_BITRATETYPE* bitrate) { ++ if (bitrate->nPortIndex != kOutputPortIndex) { ++ return OMX_ErrorUnsupportedIndex; ++ } ++ ++ mBitrate = bitrate->nTargetBitrate; ++ ++ if (bitrate->eControlRate == OMX_Video_ControlRateVariable) { ++ mBitrateControlMode = VPX_VBR; ++ } else if (bitrate->eControlRate == OMX_Video_ControlRateConstant) { ++ mBitrateControlMode = VPX_CBR; ++ } else { ++ return OMX_ErrorUnsupportedSetting; ++ } ++ ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftVPXEncoder::internalGetAndroidVpxParams( ++ OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *vpxAndroidParams) { ++ if (!isValidOMXParam(vpxAndroidParams)) { ++ android_errorWriteLog(0x534e4554, "273936601"); ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (vpxAndroidParams->nPortIndex != kOutputPortIndex) { ++ return OMX_ErrorUnsupportedIndex; ++ } ++ ++ vpxAndroidParams->nKeyFrameInterval = mKeyFrameInterval; ++ vpxAndroidParams->eTemporalPattern = mTemporalPatternType; ++ vpxAndroidParams->nTemporalLayerCount = mTemporalLayers; ++ vpxAndroidParams->nMinQuantizer = mMinQuantizer; ++ vpxAndroidParams->nMaxQuantizer = mMaxQuantizer; ++ memcpy(vpxAndroidParams->nTemporalLayerBitrateRatio, ++ mTemporalLayerBitrateRatio, sizeof(mTemporalLayerBitrateRatio)); ++ return OMX_ErrorNone; ++} ++ ++OMX_ERRORTYPE SoftVPXEncoder::internalSetAndroidVpxParams( ++ const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *vpxAndroidParams) { ++ if (!isValidOMXParam(vpxAndroidParams)) { ++ android_errorWriteLog(0x534e4554, "273937551"); ++ return OMX_ErrorBadParameter; ++ } ++ if (vpxAndroidParams->nPortIndex != kOutputPortIndex) { ++ return OMX_ErrorUnsupportedIndex; ++ } ++ if (vpxAndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternNone && ++ vpxAndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternWebRTC) { ++ return OMX_ErrorBadParameter; ++ } ++ if (vpxAndroidParams->nTemporalLayerCount > OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS) { ++ return OMX_ErrorBadParameter; ++ } ++ if (vpxAndroidParams->nMinQuantizer > vpxAndroidParams->nMaxQuantizer) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ mTemporalPatternType = vpxAndroidParams->eTemporalPattern; ++ if (vpxAndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternWebRTC) { ++ mTemporalLayers = vpxAndroidParams->nTemporalLayerCount; ++ } else if (vpxAndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternNone) { ++ mTemporalLayers = 0; ++ } ++ // Check the bitrate distribution between layers is in increasing order ++ if (mTemporalLayers > 1) { ++ for (size_t i = 0; i < mTemporalLayers - 1; i++) { ++ if (vpxAndroidParams->nTemporalLayerBitrateRatio[i + 1] <= ++ vpxAndroidParams->nTemporalLayerBitrateRatio[i]) { ++ ALOGE("Wrong bitrate ratio - should be in increasing order."); ++ return OMX_ErrorBadParameter; ++ } ++ } ++ } ++ mKeyFrameInterval = vpxAndroidParams->nKeyFrameInterval; ++ mMinQuantizer = vpxAndroidParams->nMinQuantizer; ++ mMaxQuantizer = vpxAndroidParams->nMaxQuantizer; ++ memcpy(mTemporalLayerBitrateRatio, vpxAndroidParams->nTemporalLayerBitrateRatio, ++ sizeof(mTemporalLayerBitrateRatio)); ++ ALOGD("VPx: internalSetAndroidVpxParams. BRMode: %u. TS: %zu. KF: %u." ++ " QP: %u - %u BR0: %u. BR1: %u. BR2: %u", ++ (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval, ++ mMinQuantizer, mMaxQuantizer, mTemporalLayerBitrateRatio[0], ++ mTemporalLayerBitrateRatio[1], mTemporalLayerBitrateRatio[2]); ++ return OMX_ErrorNone; ++} ++ ++vpx_enc_frame_flags_t SoftVPXEncoder::getEncodeFlags() { ++ vpx_enc_frame_flags_t flags = 0; ++ if (mTemporalPatternLength > 0) { ++ int patternIdx = mTemporalPatternIdx % mTemporalPatternLength; ++ mTemporalPatternIdx++; ++ switch (mTemporalPattern[patternIdx]) { ++ case kTemporalUpdateLast: ++ flags |= VP8_EFLAG_NO_UPD_GF; ++ flags |= VP8_EFLAG_NO_UPD_ARF; ++ flags |= VP8_EFLAG_NO_REF_GF; ++ flags |= VP8_EFLAG_NO_REF_ARF; ++ break; ++ case kTemporalUpdateGoldenWithoutDependency: ++ flags |= VP8_EFLAG_NO_REF_GF; ++ FALLTHROUGH_INTENDED; ++ case kTemporalUpdateGolden: ++ flags |= VP8_EFLAG_NO_REF_ARF; ++ flags |= VP8_EFLAG_NO_UPD_ARF; ++ flags |= VP8_EFLAG_NO_UPD_LAST; ++ break; ++ case kTemporalUpdateAltrefWithoutDependency: ++ flags |= VP8_EFLAG_NO_REF_ARF; ++ flags |= VP8_EFLAG_NO_REF_GF; ++ FALLTHROUGH_INTENDED; ++ case kTemporalUpdateAltref: ++ flags |= VP8_EFLAG_NO_UPD_GF; ++ flags |= VP8_EFLAG_NO_UPD_LAST; ++ break; ++ case kTemporalUpdateNoneNoRefAltref: ++ flags |= VP8_EFLAG_NO_REF_ARF; ++ FALLTHROUGH_INTENDED; ++ case kTemporalUpdateNone: ++ flags |= VP8_EFLAG_NO_UPD_GF; ++ flags |= VP8_EFLAG_NO_UPD_ARF; ++ flags |= VP8_EFLAG_NO_UPD_LAST; ++ flags |= VP8_EFLAG_NO_UPD_ENTROPY; ++ break; ++ case kTemporalUpdateNoneNoRefGoldenRefAltRef: ++ flags |= VP8_EFLAG_NO_REF_GF; ++ flags |= VP8_EFLAG_NO_UPD_GF; ++ flags |= VP8_EFLAG_NO_UPD_ARF; ++ flags |= VP8_EFLAG_NO_UPD_LAST; ++ flags |= VP8_EFLAG_NO_UPD_ENTROPY; ++ break; ++ case kTemporalUpdateGoldenWithoutDependencyRefAltRef: ++ flags |= VP8_EFLAG_NO_REF_GF; ++ flags |= VP8_EFLAG_NO_UPD_ARF; ++ flags |= VP8_EFLAG_NO_UPD_LAST; ++ break; ++ case kTemporalUpdateLastRefAltRef: ++ flags |= VP8_EFLAG_NO_UPD_GF; ++ flags |= VP8_EFLAG_NO_UPD_ARF; ++ flags |= VP8_EFLAG_NO_REF_GF; ++ break; ++ case kTemporalUpdateGoldenRefAltRef: ++ flags |= VP8_EFLAG_NO_UPD_ARF; ++ flags |= VP8_EFLAG_NO_UPD_LAST; ++ break; ++ case kTemporalUpdateLastAndGoldenRefAltRef: ++ flags |= VP8_EFLAG_NO_UPD_ARF; ++ flags |= VP8_EFLAG_NO_REF_GF; ++ break; ++ case kTemporalUpdateLastRefAll: ++ flags |= VP8_EFLAG_NO_UPD_ARF; ++ flags |= VP8_EFLAG_NO_UPD_GF; ++ break; ++ } ++ } ++ return flags; ++} ++ ++void SoftVPXEncoder::onQueueFilled(OMX_U32 /* portIndex */) { ++ // Initialize encoder if not already ++ if (mCodecContext == NULL) { ++ if (OK != initEncoder()) { ++ ALOGE("Failed to initialize encoder"); ++ notify(OMX_EventError, ++ OMX_ErrorUndefined, ++ 0, // Extra notification data ++ NULL); // Notification data pointer ++ return; ++ } ++ } ++ ++ vpx_codec_err_t codec_return; ++ List &inputBufferInfoQueue = getPortQueue(kInputPortIndex); ++ List &outputBufferInfoQueue = getPortQueue(kOutputPortIndex); ++ ++ while (!inputBufferInfoQueue.empty() && !outputBufferInfoQueue.empty()) { ++ BufferInfo *inputBufferInfo = *inputBufferInfoQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inputBufferHeader = inputBufferInfo->mHeader; ++ ++ BufferInfo *outputBufferInfo = *outputBufferInfoQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outputBufferHeader = outputBufferInfo->mHeader; ++ ++ if ((inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) && ++ inputBufferHeader->nFilledLen == 0) { ++ inputBufferInfoQueue.erase(inputBufferInfoQueue.begin()); ++ inputBufferInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inputBufferHeader); ++ ++ outputBufferHeader->nFilledLen = 0; ++ outputBufferHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ ++ outputBufferInfoQueue.erase(outputBufferInfoQueue.begin()); ++ outputBufferInfo->mOwnedByUs = false; ++ notifyFillBufferDone(outputBufferHeader); ++ return; ++ } ++ ++ OMX_ERRORTYPE error = validateInputBuffer(inputBufferHeader); ++ if (error != OMX_ErrorNone) { ++ ALOGE("b/27569635"); ++ android_errorWriteLog(0x534e4554, "27569635"); ++ notify(OMX_EventError, error, 0, 0); ++ return; ++ } ++ const uint8_t *source = ++ inputBufferHeader->pBuffer + inputBufferHeader->nOffset; ++ ++ size_t frameSize = mWidth * mHeight * 3 / 2; ++ if (mInputDataIsMeta) { ++ source = extractGraphicBuffer( ++ mConversionBuffer, frameSize, ++ source, inputBufferHeader->nFilledLen, ++ mWidth, mHeight); ++ if (source == NULL) { ++ ALOGE("Unable to extract gralloc buffer in metadata mode"); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); ++ return; ++ } ++ } else { ++ if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { ++ ConvertYUV420SemiPlanarToYUV420Planar( ++ source, mConversionBuffer, mWidth, mHeight); ++ ++ source = mConversionBuffer; ++ } ++ } ++ vpx_image_t raw_frame; ++ vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight, ++ kInputBufferAlignment, (uint8_t *)source); ++ ++ vpx_enc_frame_flags_t flags = getEncodeFlags(); ++ if (mKeyFrameRequested) { ++ flags |= VPX_EFLAG_FORCE_KF; ++ mKeyFrameRequested = false; ++ } ++ ++ if (mBitrateUpdated) { ++ mCodecConfiguration->rc_target_bitrate = mBitrate/1000; ++ vpx_codec_err_t res = vpx_codec_enc_config_set(mCodecContext, ++ mCodecConfiguration); ++ if (res != VPX_CODEC_OK) { ++ ALOGE("vpx encoder failed to update bitrate: %s", ++ vpx_codec_err_to_string(res)); ++ notify(OMX_EventError, ++ OMX_ErrorUndefined, ++ 0, // Extra notification data ++ NULL); // Notification data pointer ++ } ++ mBitrateUpdated = false; ++ } ++ ++ uint32_t frameDuration; ++ if (inputBufferHeader->nTimeStamp > mLastTimestamp) { ++ frameDuration = (uint32_t)(inputBufferHeader->nTimeStamp - mLastTimestamp); ++ } else { ++ // Use default of 30 fps in case of 0 frame rate. ++ uint32_t framerate = mFramerate ?: (30 << 16); ++ frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / framerate); ++ } ++ mLastTimestamp = inputBufferHeader->nTimeStamp; ++ codec_return = vpx_codec_encode( ++ mCodecContext, ++ &raw_frame, ++ inputBufferHeader->nTimeStamp, // in timebase units ++ frameDuration, // frame duration in timebase units ++ flags, // frame flags ++ VPX_DL_REALTIME); // encoding deadline ++ if (codec_return != VPX_CODEC_OK) { ++ ALOGE("vpx encoder failed to encode frame"); ++ notify(OMX_EventError, ++ OMX_ErrorUndefined, ++ 0, // Extra notification data ++ NULL); // Notification data pointer ++ return; ++ } ++ ++ vpx_codec_iter_t encoded_packet_iterator = NULL; ++ const vpx_codec_cx_pkt_t* encoded_packet; ++ ++ while ((encoded_packet = vpx_codec_get_cx_data( ++ mCodecContext, &encoded_packet_iterator))) { ++ if (encoded_packet->kind == VPX_CODEC_CX_FRAME_PKT) { ++ outputBufferHeader->nTimeStamp = encoded_packet->data.frame.pts; ++ outputBufferHeader->nFlags = 0; ++ if (encoded_packet->data.frame.flags & VPX_FRAME_IS_KEY) ++ outputBufferHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME; ++ outputBufferHeader->nOffset = 0; ++ outputBufferHeader->nFilledLen = encoded_packet->data.frame.sz; ++ if (outputBufferHeader->nFilledLen > outputBufferHeader->nAllocLen) { ++ android_errorWriteLog(0x534e4554, "27569635"); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); ++ return; ++ } ++ memcpy(outputBufferHeader->pBuffer, ++ encoded_packet->data.frame.buf, ++ encoded_packet->data.frame.sz); ++ outputBufferInfo->mOwnedByUs = false; ++ outputBufferInfoQueue.erase(outputBufferInfoQueue.begin()); ++ if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ outputBufferHeader->nFlags |= OMX_BUFFERFLAG_EOS; ++ } ++ notifyFillBufferDone(outputBufferHeader); ++ } ++ } ++ ++ inputBufferInfo->mOwnedByUs = false; ++ inputBufferInfoQueue.erase(inputBufferInfoQueue.begin()); ++ notifyEmptyBufferDone(inputBufferHeader); ++ } ++} ++ ++void SoftVPXEncoder::onReset() { ++ releaseEncoder(); ++ mLastTimestamp = 0x7FFFFFFFFFFFFFFFLL; ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ if (!strcmp(name, "OMX.google.vp8.encoder")) { ++ return new android::SoftVP8Encoder(name, callbacks, appData, component); ++ } else if (!strcmp(name, "OMX.google.vp9.encoder")) { ++ return new android::SoftVP9Encoder(name, callbacks, appData, component); ++ } else { ++ CHECK(!"Unknown component"); ++ } ++ return NULL; ++} +diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h +new file mode 100644 +index 0000000..7208d69 +--- /dev/null ++++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h +@@ -0,0 +1,251 @@ ++/* ++ * Copyright (C) 2013 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 SOFT_VPX_ENCODER_H_ ++ ++#define SOFT_VPX_ENCODER_H_ ++ ++#include ++ ++#include ++#include ++ ++#include "vpx/vpx_encoder.h" ++#include "vpx/vpx_codec.h" ++#include "vpx/vp8cx.h" ++ ++namespace android { ++ ++// Base class for a VPX Encoder OMX Component ++// ++// Boilerplate for callback bindings are taken care ++// by the base class SimpleSoftOMXComponent and its ++// parent SoftOMXComponent. ++// ++// Only following encoder settings are available (codec specific settings might ++// be available in the sub-classes): ++// - target bitrate ++// - rate control (constant / variable) ++// - frame rate ++// - error resilience ++// - reconstruction & loop filters (g_profile) ++// ++// Only following color formats are recognized ++// - YUV420Planar ++// - YUV420SemiPlanar ++// - AndroidOpaque ++// ++// Following settings are not configurable by the client ++// - encoding deadline is realtime ++// - multithreaded encoding utilizes a number of threads equal ++// to online cpu's available ++// - the algorithm interface for encoder is decided by the sub-class in use ++// - fractional bits of frame rate is discarded ++// - OMX timestamps are in microseconds, therefore ++// encoder timebase is fixed to 1/1000000 ++ ++struct SoftVPXEncoder : public SoftVideoEncoderOMXComponent { ++ SoftVPXEncoder(const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component, ++ const char* role, ++ OMX_VIDEO_CODINGTYPE codingType, ++ const char* mimeType, ++ int32_t minCompressionRatio, ++ const CodecProfileLevel *profileLevels, ++ size_t numProfileLevels); ++ ++protected: ++ virtual ~SoftVPXEncoder(); ++ ++ // Returns current values for requested OMX ++ // parameters ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR param); ++ ++ // Validates, extracts and stores relevant OMX ++ // parameters ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR param); ++ ++ virtual OMX_ERRORTYPE internalSetConfig( ++ OMX_INDEXTYPE index, const OMX_PTR params, bool *frameConfig); ++ ++ // OMX callback when buffers available ++ // Note that both an input and output buffer ++ // is expected to be available to carry out ++ // encoding of the frame ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ ++ virtual void onReset(); ++ ++ // Initializes vpx encoder with available settings. ++ status_t initEncoder(); ++ ++ // Populates mCodecInterface with codec specific settings. ++ virtual void setCodecSpecificInterface() = 0; ++ ++ // Sets codec specific configuration. ++ virtual void setCodecSpecificConfiguration() = 0; ++ ++ // Sets codec specific encoder controls. ++ virtual vpx_codec_err_t setCodecSpecificControls() = 0; ++ ++ // Get current encode flags. ++ virtual vpx_enc_frame_flags_t getEncodeFlags(); ++ ++ // Releases vpx encoder instance, with it's associated ++ // data structures. ++ // ++ // Unless called earlier, this is handled by the ++ // dtor. ++ status_t releaseEncoder(); ++ ++ // Get bitrate parameters. ++ virtual OMX_ERRORTYPE internalGetBitrateParams( ++ OMX_VIDEO_PARAM_BITRATETYPE* bitrate); ++ ++ // Updates bitrate to reflect port settings. ++ virtual OMX_ERRORTYPE internalSetBitrateParams( ++ const OMX_VIDEO_PARAM_BITRATETYPE* bitrate); ++ ++ // Gets Android vpx specific parameters. ++ OMX_ERRORTYPE internalGetAndroidVpxParams( ++ OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *vpxAndroidParams); ++ ++ // Handles Android vpx specific parameters. ++ OMX_ERRORTYPE internalSetAndroidVpxParams( ++ const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *vpxAndroidParams); ++ ++ enum TemporalReferences { ++ // For 1 layer case: reference all (last, golden, and alt ref), but only ++ // update last. ++ kTemporalUpdateLastRefAll = 12, ++ // First base layer frame for 3 temporal layers, which updates last and ++ // golden with alt ref dependency. ++ kTemporalUpdateLastAndGoldenRefAltRef = 11, ++ // First enhancement layer with alt ref dependency. ++ kTemporalUpdateGoldenRefAltRef = 10, ++ // First enhancement layer with alt ref dependency. ++ kTemporalUpdateGoldenWithoutDependencyRefAltRef = 9, ++ // Base layer with alt ref dependency. ++ kTemporalUpdateLastRefAltRef = 8, ++ // Highest enhacement layer without dependency on golden with alt ref ++ // dependency. ++ kTemporalUpdateNoneNoRefGoldenRefAltRef = 7, ++ // Second layer and last frame in cycle, for 2 layers. ++ kTemporalUpdateNoneNoRefAltref = 6, ++ // Highest enhancement layer. ++ kTemporalUpdateNone = 5, ++ // Second enhancement layer. ++ kTemporalUpdateAltref = 4, ++ // Second enhancement layer without dependency on previous frames in ++ // the second enhancement layer. ++ kTemporalUpdateAltrefWithoutDependency = 3, ++ // First enhancement layer. ++ kTemporalUpdateGolden = 2, ++ // First enhancement layer without dependency on previous frames in ++ // the first enhancement layer. ++ kTemporalUpdateGoldenWithoutDependency = 1, ++ // Base layer. ++ kTemporalUpdateLast = 0, ++ }; ++ enum { ++ kMaxTemporalPattern = 8 ++ }; ++ ++ // number of buffers allocated per port ++ static const uint32_t kNumBuffers = 4; ++ ++ // OMX port indexes that refer to input and ++ // output ports respectively ++ static const uint32_t kInputPortIndex = 0; ++ static const uint32_t kOutputPortIndex = 1; ++ ++ // Byte-alignment required for buffers ++ static const uint32_t kInputBufferAlignment = 1; ++ static const uint32_t kOutputBufferAlignment = 2; ++ ++ // Number of supported input color formats ++ static const uint32_t kNumberOfSupportedColorFormats = 3; ++ ++ // vpx specific opaque data structure that ++ // stores encoder state ++ vpx_codec_ctx_t* mCodecContext; ++ ++ // vpx specific data structure that ++ // stores encoder configuration ++ vpx_codec_enc_cfg_t* mCodecConfiguration; ++ ++ // vpx specific read-only data structure ++ // that specifies algorithm interface (e.g. vp8) ++ vpx_codec_iface_t* mCodecInterface; ++ ++ // If a request for a change it bitrate has been received. ++ bool mBitrateUpdated; ++ ++ // Bitrate control mode, either constant or variable ++ vpx_rc_mode mBitrateControlMode; ++ ++ // Parameter that denotes whether error resilience ++ // is enabled in encoder ++ OMX_BOOL mErrorResilience; ++ ++ // Key frame interval in frames ++ uint32_t mKeyFrameInterval; ++ ++ // Minimum (best quality) quantizer ++ uint32_t mMinQuantizer; ++ ++ // Maximum (worst quality) quantizer ++ uint32_t mMaxQuantizer; ++ ++ // Number of coding temporal layers to be used. ++ size_t mTemporalLayers; ++ ++ // Temporal layer bitrare ratio in percentage ++ uint32_t mTemporalLayerBitrateRatio[OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS]; ++ ++ // Temporal pattern type ++ OMX_VIDEO_ANDROID_VPXTEMPORALLAYERPATTERNTYPE mTemporalPatternType; ++ ++ // Temporal pattern length ++ size_t mTemporalPatternLength; ++ ++ // Temporal pattern current index ++ size_t mTemporalPatternIdx; ++ ++ // Frame type temporal pattern ++ TemporalReferences mTemporalPattern[kMaxTemporalPattern]; ++ ++ // Last input buffer timestamp ++ OMX_TICKS mLastTimestamp; ++ ++ // Conversion buffer is needed to convert semi ++ // planar yuv420 to planar format ++ // It is only allocated if input format is ++ // indeed YUV420SemiPlanar. ++ uint8_t* mConversionBuffer; ++ ++ bool mKeyFrameRequested; ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftVPXEncoder); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_VPX_ENCODER_H_ +diff --git a/media/libstagefright/codecs/on2/enc/exports.lds b/media/libstagefright/codecs/on2/enc/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/on2/enc/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/opus/dec/Android.bp b/media/libstagefright/codecs/opus/dec/Android.bp +new file mode 100644 +index 0000000..3d8af69 +--- /dev/null ++++ b/media/libstagefright/codecs/opus/dec/Android.bp +@@ -0,0 +1,29 @@ ++package { ++ // See: http://go/android-license-faq ++ // A large-scale-change added 'default_applicable_licenses' to import ++ // all of the 'license_kinds' from "frameworks_av_media_libstagefright_license" ++ // to get the below license kinds: ++ // SPDX-license-identifier-Apache-2.0 ++ default_applicable_licenses: ["frameworks_av_media_libstagefright_license"], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_opusdec", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: ["SoftOpus.cpp"], ++ ++ shared_libs: [ ++ "libopus", ++ ], ++ ++ version_script: "exports.lds", ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ "unsigned-integer-overflow", ++ ], ++ cfi: true, ++ }, ++} +diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp +new file mode 100644 +index 0000000..dcd8dda +--- /dev/null ++++ b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp +@@ -0,0 +1,674 @@ ++/* ++ * Copyright (C) 2014 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 "SoftOpus" ++#include ++ ++#include "SoftOpus.h" ++#include ++#include ++ ++#include ++#include ++ ++extern "C" { ++ #include ++ #include ++} ++ ++namespace android { ++ ++static const int kRate = 48000; ++ ++// Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies ++// mappings for up to 8 channels. This information is part of the Vorbis I ++// Specification: ++// http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html ++static const int kMaxChannels = 8; ++ ++template ++static void InitOMXParams(T *params) { ++ params->nSize = sizeof(T); ++ params->nVersion.s.nVersionMajor = 1; ++ params->nVersion.s.nVersionMinor = 0; ++ params->nVersion.s.nRevision = 0; ++ params->nVersion.s.nStep = 0; ++} ++ ++SoftOpus::SoftOpus( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SimpleSoftOMXComponent(name, callbacks, appData, component), ++ mInputBufferCount(0), ++ mDecoder(NULL), ++ mHeader(NULL), ++ mNumChannels(1), ++ mSamplingRate(kRate), ++ mCodecDelay(0), ++ mSeekPreRoll(0), ++ mAnchorTimeUs(0), ++ mNumFramesOutput(0), ++ mHaveEOS(false), ++ mOutputPortSettingsChange(NONE) { ++ initPorts(); ++ CHECK_EQ(initDecoder(), (status_t)OK); ++} ++ ++SoftOpus::~SoftOpus() { ++ if (mDecoder != NULL) { ++ opus_multistream_decoder_destroy(mDecoder); ++ mDecoder = NULL; ++ } ++ if (mHeader != NULL) { ++ delete mHeader; ++ mHeader = NULL; ++ } ++} ++ ++void SoftOpus::initPorts() { ++ OMX_PARAM_PORTDEFINITIONTYPE def; ++ InitOMXParams(&def); ++ ++ def.nPortIndex = 0; ++ def.eDir = OMX_DirInput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = 960 * 6; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 1; ++ ++ def.format.audio.cMIMEType = ++ const_cast(MEDIA_MIMETYPE_AUDIO_OPUS); ++ ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = ++ (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidOPUS; ++ ++ addPort(def); ++ ++ def.nPortIndex = 1; ++ def.eDir = OMX_DirOutput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t) * kMaxChannels; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 2; ++ ++ def.format.audio.cMIMEType = const_cast("audio/raw"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; ++ ++ addPort(def); ++} ++ ++status_t SoftOpus::initDecoder() { ++ return OK; ++} ++ ++OMX_ERRORTYPE SoftOpus::internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params) { ++ switch ((int)index) { ++ case OMX_IndexParamAudioPortFormat: ++ { ++ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (formatParams->nIndex > 0) { ++ return OMX_ErrorNoMore; ++ } ++ ++ formatParams->eEncoding = ++ (formatParams->nPortIndex == 0) ++ ? (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidOPUS : ++ OMX_AUDIO_CodingPCM; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioAndroidOpus: ++ { ++ OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *opusParams = ++ (OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *)params; ++ ++ if (!isValidOMXParam(opusParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (opusParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ opusParams->nAudioBandWidth = 0; ++ opusParams->nSampleRate = mSamplingRate; ++ opusParams->nBitRate = 0; ++ ++ if (!isConfigured()) { ++ opusParams->nChannels = mNumChannels; ++ } else { ++ opusParams->nChannels = mHeader->channels; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ pcmParams->eNumData = OMX_NumericalDataSigned; ++ pcmParams->eEndian = OMX_EndianBig; ++ pcmParams->bInterleaved = OMX_TRUE; ++ pcmParams->nBitPerSample = 16; ++ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; ++ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; ++ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; ++ pcmParams->nSamplingRate = kRate; ++ ++ if (!isConfigured()) { ++ pcmParams->nChannels = 1; ++ } else { ++ pcmParams->nChannels = mHeader->channels; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalGetParameter(index, params); ++ } ++} ++ ++OMX_ERRORTYPE SoftOpus::internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params) { ++ switch ((int)index) { ++ case OMX_IndexParamStandardComponentRole: ++ { ++ const OMX_PARAM_COMPONENTROLETYPE *roleParams = ++ (const OMX_PARAM_COMPONENTROLETYPE *)params; ++ ++ if (!isValidOMXParam(roleParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (strncmp((const char *)roleParams->cRole, ++ "audio_decoder.opus", ++ OMX_MAX_STRINGNAME_SIZE - 1)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPortFormat: ++ { ++ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if ((formatParams->nPortIndex == 0 ++ && formatParams->eEncoding != ++ (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidOPUS) ++ || (formatParams->nPortIndex == 1 ++ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioAndroidOpus: ++ { ++ const OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *opusParams = ++ (const OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *)params; ++ ++ if (!isValidOMXParam(opusParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (opusParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ mNumChannels = opusParams->nChannels; ++ mSamplingRate = opusParams->nSampleRate; ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalSetParameter(index, params); ++ } ++} ++ ++bool SoftOpus::isConfigured() const { ++ return mInputBufferCount >= 1; ++} ++ ++static uint16_t ReadLE16(const uint8_t *data, size_t data_size, ++ uint32_t read_offset) { ++ if (read_offset + 1 > data_size) ++ return 0; ++ uint16_t val; ++ val = data[read_offset]; ++ val |= data[read_offset + 1] << 8; ++ return val; ++} ++ ++// Maximum packet size used in Xiph's opusdec. ++static const int kMaxOpusOutputPacketSizeSamples = 960 * 6; ++ ++// Default audio output channel layout. Used to initialize |stream_map| in ++// OpusHeader, and passed to opus_multistream_decoder_create() when the header ++// does not contain mapping information. The values are valid only for mono and ++// stereo output: Opus streams with more than 2 channels require a stream map. ++static const int kMaxChannelsWithDefaultLayout = 2; ++static const uint8_t kDefaultOpusChannelLayout[kMaxChannelsWithDefaultLayout] = { 0, 1 }; ++ ++// Parses Opus Header. Header spec: http://wiki.xiph.org/OggOpus#ID_Header ++static bool ParseOpusHeader(const uint8_t *data, size_t data_size, ++ OpusHeader* header) { ++ // Size of the Opus header excluding optional mapping information. ++ const size_t kOpusHeaderSize = 19; ++ ++ // Offset to the channel count byte in the Opus header. ++ const size_t kOpusHeaderChannelsOffset = 9; ++ ++ // Offset to the pre-skip value in the Opus header. ++ const size_t kOpusHeaderSkipSamplesOffset = 10; ++ ++ // Offset to the gain value in the Opus header. ++ const size_t kOpusHeaderGainOffset = 16; ++ ++ // Offset to the channel mapping byte in the Opus header. ++ const size_t kOpusHeaderChannelMappingOffset = 18; ++ ++ // Opus Header contains a stream map. The mapping values are in the header ++ // beyond the always present |kOpusHeaderSize| bytes of data. The mapping ++ // data contains stream count, coupling information, and per channel mapping ++ // values: ++ // - Byte 0: Number of streams. ++ // - Byte 1: Number coupled. ++ // - Byte 2: Starting at byte 2 are |header->channels| uint8 mapping ++ // values. ++ const size_t kOpusHeaderNumStreamsOffset = kOpusHeaderSize; ++ const size_t kOpusHeaderNumCoupledOffset = kOpusHeaderNumStreamsOffset + 1; ++ const size_t kOpusHeaderStreamMapOffset = kOpusHeaderNumStreamsOffset + 2; ++ ++ if (data_size < kOpusHeaderSize) { ++ ALOGV("Header size is too small."); ++ return false; ++ } ++ header->channels = *(data + kOpusHeaderChannelsOffset); ++ ++ if (header->channels <= 0 || header->channels > kMaxChannels) { ++ ALOGV("Invalid Header, wrong channel count: %d", header->channels); ++ return false; ++ } ++ header->skip_samples = ReadLE16(data, data_size, ++ kOpusHeaderSkipSamplesOffset); ++ header->gain_db = static_cast( ++ ReadLE16(data, data_size, ++ kOpusHeaderGainOffset)); ++ header->channel_mapping = *(data + kOpusHeaderChannelMappingOffset); ++ if (!header->channel_mapping) { ++ if (header->channels > kMaxChannelsWithDefaultLayout) { ++ ALOGV("Invalid Header, missing stream map."); ++ return false; ++ } ++ header->num_streams = 1; ++ header->num_coupled = header->channels > 1; ++ header->stream_map[0] = 0; ++ header->stream_map[1] = 1; ++ return true; ++ } ++ if (data_size < kOpusHeaderStreamMapOffset + header->channels) { ++ ALOGV("Invalid stream map; insufficient data for current channel " ++ "count: %d", header->channels); ++ return false; ++ } ++ header->num_streams = *(data + kOpusHeaderNumStreamsOffset); ++ header->num_coupled = *(data + kOpusHeaderNumCoupledOffset); ++ if (header->num_streams + header->num_coupled != header->channels) { ++ ALOGV("Inconsistent channel mapping."); ++ return false; ++ } ++ for (int i = 0; i < header->channels; ++i) ++ header->stream_map[i] = *(data + kOpusHeaderStreamMapOffset + i); ++ return true; ++} ++ ++// Convert nanoseconds to number of samples. ++static uint64_t ns_to_samples(uint64_t ns, int kRate) { ++ return static_cast(ns) * kRate / 1000000000; ++} ++ ++void SoftOpus::handleEOS() { ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ CHECK(!inQueue.empty() && !outQueue.empty()); ++ ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ outHeader->nFilledLen = 0; ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ mHaveEOS = true; ++ ++ outQueue.erase(outQueue.begin()); ++ outInfo->mOwnedByUs = false; ++ notifyFillBufferDone(outHeader); ++ ++ BufferInfo *inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ ++ ++mInputBufferCount; ++} ++ ++void SoftOpus::onQueueFilled(OMX_U32 /* portIndex */) { ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ ++ if (mOutputPortSettingsChange != NONE) { ++ return; ++ } ++ ++ while (!mHaveEOS && !inQueue.empty() && !outQueue.empty()) { ++ BufferInfo *inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++ ++ if (mInputBufferCount < 3) { ++ const uint8_t *data = inHeader->pBuffer + inHeader->nOffset; ++ size_t size = inHeader->nFilledLen; ++ ++ if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && size == 0) { ++ handleEOS(); ++ return; ++ } ++ ++ if (size < sizeof(int64_t)) { ++ // The 2nd and 3rd input buffer are expected to contain ++ // an int64_t (see below), so make sure we get at least ++ // that much. The first input buffer must contain 19 bytes, ++ // but that is checked already. ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ ++ if (mInputBufferCount == 0) { ++ delete mHeader; ++ mHeader = new OpusHeader(); ++ memset(mHeader, 0, sizeof(*mHeader)); ++ if (!ParseOpusHeader(data, size, mHeader)) { ++ ALOGV("Parsing Opus Header failed."); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ ++ uint8_t channel_mapping[kMaxChannels] = {0}; ++ if (mHeader->channels <= kMaxChannelsWithDefaultLayout) { ++ memcpy(&channel_mapping, ++ kDefaultOpusChannelLayout, ++ kMaxChannelsWithDefaultLayout); ++ } else { ++ memcpy(&channel_mapping, ++ mHeader->stream_map, ++ mHeader->channels); ++ } ++ ++ int status = OPUS_INVALID_STATE; ++ if (mDecoder != NULL) { ++ opus_multistream_decoder_destroy(mDecoder); ++ } ++ mDecoder = opus_multistream_decoder_create(kRate, ++ mHeader->channels, ++ mHeader->num_streams, ++ mHeader->num_coupled, ++ channel_mapping, ++ &status); ++ if (!mDecoder || status != OPUS_OK) { ++ ALOGV("opus_multistream_decoder_create failed status=%s", ++ opus_strerror(status)); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ status = ++ opus_multistream_decoder_ctl(mDecoder, ++ OPUS_SET_GAIN(mHeader->gain_db)); ++ if (status != OPUS_OK) { ++ ALOGV("Failed to set OPUS header gain; status=%s", ++ opus_strerror(status)); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ } else if (mInputBufferCount == 1) { ++ mCodecDelay = ns_to_samples( ++ *(reinterpret_cast(inHeader->pBuffer + ++ inHeader->nOffset)), ++ kRate); ++ mSamplesToDiscard = mCodecDelay; ++ } else { ++ mSeekPreRoll = ns_to_samples( ++ *(reinterpret_cast(inHeader->pBuffer + ++ inHeader->nOffset)), ++ kRate); ++ mSamplingRate = kRate; ++ mNumChannels = mHeader->channels; ++ notify(OMX_EventPortSettingsChanged, 1, 0, NULL); ++ mOutputPortSettingsChange = AWAITING_DISABLED; ++ } ++ ++ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ handleEOS(); ++ return; ++ } ++ ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ ++mInputBufferCount; ++ ++ continue; ++ } ++ ++ // Ignore CSD re-submissions. ++ if (mInputBufferCount >= 3 && (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) { ++ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ handleEOS(); ++ return; ++ } ++ ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ continue; ++ } ++ ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ ++ if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) { ++ handleEOS(); ++ return; ++ } ++ ++ if (inHeader->nOffset == 0) { ++ mAnchorTimeUs = inHeader->nTimeStamp; ++ mNumFramesOutput = 0; ++ } ++ ++ // When seeking to zero, |mCodecDelay| samples has to be discarded ++ // instead of |mSeekPreRoll| samples (as we would when seeking to any ++ // other timestamp). ++ if (inHeader->nTimeStamp == 0) { ++ mSamplesToDiscard = mCodecDelay; ++ } ++ ++ const uint8_t *data = inHeader->pBuffer + inHeader->nOffset; ++ const uint32_t size = inHeader->nFilledLen; ++ size_t frameSize = kMaxOpusOutputPacketSizeSamples; ++ if (frameSize > outHeader->nAllocLen / sizeof(int16_t) / mHeader->channels) { ++ frameSize = outHeader->nAllocLen / sizeof(int16_t) / mHeader->channels; ++ android_errorWriteLog(0x534e4554, "27833616"); ++ } ++ ++ int numFrames = opus_multistream_decode(mDecoder, ++ data, ++ size, ++ (int16_t *)outHeader->pBuffer, ++ frameSize, ++ 0); ++ if (numFrames < 0) { ++ ALOGE("opus_multistream_decode returned %d", numFrames); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ ++ outHeader->nOffset = 0; ++ if (mSamplesToDiscard > 0) { ++ if (mSamplesToDiscard > numFrames) { ++ mSamplesToDiscard -= numFrames; ++ numFrames = 0; ++ } else { ++ numFrames -= mSamplesToDiscard; ++ outHeader->nOffset = mSamplesToDiscard * sizeof(int16_t) * ++ mHeader->channels; ++ mSamplesToDiscard = 0; ++ } ++ } ++ ++ outHeader->nFilledLen = numFrames * sizeof(int16_t) * mHeader->channels; ++ ++ outHeader->nTimeStamp = mAnchorTimeUs + ++ (mNumFramesOutput * 1000000LL) / ++ kRate; ++ ++ mNumFramesOutput += numFrames; ++ ++ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ mHaveEOS = true; ++ } else { ++ outHeader->nFlags = 0; ++ } ++ ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ notifyEmptyBufferDone(inHeader); ++ ++mInputBufferCount; ++ ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ notifyFillBufferDone(outHeader); ++ } ++} ++ ++void SoftOpus::onPortFlushCompleted(OMX_U32 portIndex) { ++ if (portIndex == 0 && mDecoder != NULL) { ++ // Make sure that the next buffer output does not still ++ // depend on fragments from the last one decoded. ++ mNumFramesOutput = 0; ++ opus_multistream_decoder_ctl(mDecoder, OPUS_RESET_STATE); ++ mAnchorTimeUs = 0; ++ mSamplesToDiscard = mSeekPreRoll; ++ mHaveEOS = false; ++ } ++} ++ ++void SoftOpus::onReset() { ++ mInputBufferCount = 0; ++ mNumFramesOutput = 0; ++ if (mDecoder != NULL) { ++ opus_multistream_decoder_destroy(mDecoder); ++ mDecoder = NULL; ++ } ++ if (mHeader != NULL) { ++ delete mHeader; ++ mHeader = NULL; ++ } ++ ++ mOutputPortSettingsChange = NONE; ++ mHaveEOS = false; ++} ++ ++void SoftOpus::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { ++ if (portIndex != 1) { ++ return; ++ } ++ ++ switch (mOutputPortSettingsChange) { ++ case NONE: ++ break; ++ ++ case AWAITING_DISABLED: ++ { ++ CHECK(!enabled); ++ mOutputPortSettingsChange = AWAITING_ENABLED; ++ break; ++ } ++ ++ default: ++ { ++ CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); ++ CHECK(enabled); ++ mOutputPortSettingsChange = NONE; ++ break; ++ } ++ } ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ return new android::SoftOpus(name, callbacks, appData, component); ++} +diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.h b/media/libstagefright/codecs/opus/dec/SoftOpus.h +new file mode 100644 +index 0000000..00058c8 +--- /dev/null ++++ b/media/libstagefright/codecs/opus/dec/SoftOpus.h +@@ -0,0 +1,98 @@ ++/* ++ * Copyright (C) 2014 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. ++ */ ++ ++/* ++ * The Opus specification is part of IETF RFC 6716: ++ * http://tools.ietf.org/html/rfc6716 ++ */ ++ ++#ifndef SOFT_OPUS_H_ ++ ++#define SOFT_OPUS_H_ ++ ++#include ++ ++struct OpusMSDecoder; ++ ++namespace android { ++ ++struct OpusHeader { ++ int channels; ++ int skip_samples; ++ int channel_mapping; ++ int num_streams; ++ int num_coupled; ++ int16_t gain_db; ++ uint8_t stream_map[8]; ++}; ++ ++struct SoftOpus : public SimpleSoftOMXComponent { ++ SoftOpus(const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++protected: ++ virtual ~SoftOpus(); ++ ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params); ++ ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ virtual void onPortFlushCompleted(OMX_U32 portIndex); ++ virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled); ++ virtual void onReset(); ++ ++private: ++ enum { ++ kNumBuffers = 4, ++ kMaxNumSamplesPerBuffer = 960 * 6 ++ }; ++ ++ size_t mInputBufferCount; ++ ++ OpusMSDecoder *mDecoder; ++ OpusHeader *mHeader; ++ ++ int32_t mNumChannels; ++ int32_t mSamplingRate; ++ int64_t mCodecDelay; ++ int64_t mSeekPreRoll; ++ int64_t mSamplesToDiscard; ++ int64_t mAnchorTimeUs; ++ int64_t mNumFramesOutput; ++ bool mHaveEOS; ++ ++ enum { ++ NONE, ++ AWAITING_DISABLED, ++ AWAITING_ENABLED ++ } mOutputPortSettingsChange; ++ ++ void initPorts(); ++ status_t initDecoder(); ++ bool isConfigured() const; ++ void handleEOS(); ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftOpus); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_OPUS_H_ +diff --git a/media/libstagefright/codecs/opus/dec/exports.lds b/media/libstagefright/codecs/opus/dec/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/opus/dec/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/raw/Android.bp b/media/libstagefright/codecs/raw/Android.bp +new file mode 100644 +index 0000000..3673786 +--- /dev/null ++++ b/media/libstagefright/codecs/raw/Android.bp +@@ -0,0 +1,35 @@ ++package { ++ default_applicable_licenses: [ ++ "frameworks_av_media_libstagefright_codecs_raw_license", ++ ], ++} ++ ++// Added automatically by a large-scale-change ++// See: http://go/android-license-faq ++license { ++ name: "frameworks_av_media_libstagefright_codecs_raw_license", ++ visibility: [":__subpackages__"], ++ license_kinds: [ ++ "SPDX-license-identifier-Apache-2.0", ++ ], ++ license_text: [ ++ "NOTICE", ++ ], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_rawdec", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: ["SoftRaw.cpp"], ++ ++ version_script: "exports.lds", ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ "unsigned-integer-overflow", ++ ], ++ cfi: true, ++ }, ++} +diff --git a/media/libstagefright/codecs/raw/MODULE_LICENSE_APACHE2 b/media/libstagefright/codecs/raw/MODULE_LICENSE_APACHE2 +new file mode 100644 +index 0000000..e69de29 +diff --git a/media/libstagefright/codecs/raw/NOTICE b/media/libstagefright/codecs/raw/NOTICE +new file mode 100644 +index 0000000..c5b1efa +--- /dev/null ++++ b/media/libstagefright/codecs/raw/NOTICE +@@ -0,0 +1,190 @@ ++ ++ Copyright (c) 2005-2008, 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. ++ ++ 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. ++ ++ ++ Apache License ++ Version 2.0, January 2004 ++ http://www.apache.org/licenses/ ++ ++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION ++ ++ 1. Definitions. ++ ++ "License" shall mean the terms and conditions for use, reproduction, ++ and distribution as defined by Sections 1 through 9 of this document. ++ ++ "Licensor" shall mean the copyright owner or entity authorized by ++ the copyright owner that is granting the License. ++ ++ "Legal Entity" shall mean the union of the acting entity and all ++ other entities that control, are controlled by, or are under common ++ control with that entity. For the purposes of this definition, ++ "control" means (i) the power, direct or indirect, to cause the ++ direction or management of such entity, whether by contract or ++ otherwise, or (ii) ownership of fifty percent (50%) or more of the ++ outstanding shares, or (iii) beneficial ownership of such entity. ++ ++ "You" (or "Your") shall mean an individual or Legal Entity ++ exercising permissions granted by this License. ++ ++ "Source" form shall mean the preferred form for making modifications, ++ including but not limited to software source code, documentation ++ source, and configuration files. ++ ++ "Object" form shall mean any form resulting from mechanical ++ transformation or translation of a Source form, including but ++ not limited to compiled object code, generated documentation, ++ and conversions to other media types. ++ ++ "Work" shall mean the work of authorship, whether in Source or ++ Object form, made available under the License, as indicated by a ++ copyright notice that is included in or attached to the work ++ (an example is provided in the Appendix below). ++ ++ "Derivative Works" shall mean any work, whether in Source or Object ++ form, that is based on (or derived from) the Work and for which the ++ editorial revisions, annotations, elaborations, or other modifications ++ represent, as a whole, an original work of authorship. For the purposes ++ of this License, Derivative Works shall not include works that remain ++ separable from, or merely link (or bind by name) to the interfaces of, ++ the Work and Derivative Works thereof. ++ ++ "Contribution" shall mean any work of authorship, including ++ the original version of the Work and any modifications or additions ++ to that Work or Derivative Works thereof, that is intentionally ++ submitted to Licensor for inclusion in the Work by the copyright owner ++ or by an individual or Legal Entity authorized to submit on behalf of ++ the copyright owner. For the purposes of this definition, "submitted" ++ means any form of electronic, verbal, or written communication sent ++ to the Licensor or its representatives, including but not limited to ++ communication on electronic mailing lists, source code control systems, ++ and issue tracking systems that are managed by, or on behalf of, the ++ Licensor for the purpose of discussing and improving the Work, but ++ excluding communication that is conspicuously marked or otherwise ++ designated in writing by the copyright owner as "Not a Contribution." ++ ++ "Contributor" shall mean Licensor and any individual or Legal Entity ++ on behalf of whom a Contribution has been received by Licensor and ++ subsequently incorporated within the Work. ++ ++ 2. Grant of Copyright License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ copyright license to reproduce, prepare Derivative Works of, ++ publicly display, publicly perform, sublicense, and distribute the ++ Work and such Derivative Works in Source or Object form. ++ ++ 3. Grant of Patent License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ (except as stated in this section) patent license to make, have made, ++ use, offer to sell, sell, import, and otherwise transfer the Work, ++ where such license applies only to those patent claims licensable ++ by such Contributor that are necessarily infringed by their ++ Contribution(s) alone or by combination of their Contribution(s) ++ with the Work to which such Contribution(s) was submitted. If You ++ institute patent litigation against any entity (including a ++ cross-claim or counterclaim in a lawsuit) alleging that the Work ++ or a Contribution incorporated within the Work constitutes direct ++ or contributory patent infringement, then any patent licenses ++ granted to You under this License for that Work shall terminate ++ as of the date such litigation is filed. ++ ++ 4. Redistribution. You may reproduce and distribute copies of the ++ Work or Derivative Works thereof in any medium, with or without ++ modifications, and in Source or Object form, provided that You ++ meet the following conditions: ++ ++ (a) You must give any other recipients of the Work or ++ Derivative Works a copy of this License; and ++ ++ (b) You must cause any modified files to carry prominent notices ++ stating that You changed the files; and ++ ++ (c) You must retain, in the Source form of any Derivative Works ++ that You distribute, all copyright, patent, trademark, and ++ attribution notices from the Source form of the Work, ++ excluding those notices that do not pertain to any part of ++ the Derivative Works; and ++ ++ (d) If the Work includes a "NOTICE" text file as part of its ++ distribution, then any Derivative Works that You distribute must ++ include a readable copy of the attribution notices contained ++ within such NOTICE file, excluding those notices that do not ++ pertain to any part of the Derivative Works, in at least one ++ of the following places: within a NOTICE text file distributed ++ as part of the Derivative Works; within the Source form or ++ documentation, if provided along with the Derivative Works; or, ++ within a display generated by the Derivative Works, if and ++ wherever such third-party notices normally appear. The contents ++ of the NOTICE file are for informational purposes only and ++ do not modify the License. You may add Your own attribution ++ notices within Derivative Works that You distribute, alongside ++ or as an addendum to the NOTICE text from the Work, provided ++ that such additional attribution notices cannot be construed ++ as modifying the License. ++ ++ You may add Your own copyright statement to Your modifications and ++ may provide additional or different license terms and conditions ++ for use, reproduction, or distribution of Your modifications, or ++ for any such Derivative Works as a whole, provided Your use, ++ reproduction, and distribution of the Work otherwise complies with ++ the conditions stated in this License. ++ ++ 5. Submission of Contributions. Unless You explicitly state otherwise, ++ any Contribution intentionally submitted for inclusion in the Work ++ by You to the Licensor shall be under the terms and conditions of ++ this License, without any additional terms or conditions. ++ Notwithstanding the above, nothing herein shall supersede or modify ++ the terms of any separate license agreement you may have executed ++ with Licensor regarding such Contributions. ++ ++ 6. Trademarks. This License does not grant permission to use the trade ++ names, trademarks, service marks, or product names of the Licensor, ++ except as required for reasonable and customary use in describing the ++ origin of the Work and reproducing the content of the NOTICE file. ++ ++ 7. Disclaimer of Warranty. Unless required by applicable law or ++ agreed to in writing, Licensor provides the Work (and each ++ Contributor provides its Contributions) on an "AS IS" BASIS, ++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or ++ implied, including, without limitation, any warranties or conditions ++ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A ++ PARTICULAR PURPOSE. You are solely responsible for determining the ++ appropriateness of using or redistributing the Work and assume any ++ risks associated with Your exercise of permissions under this License. ++ ++ 8. Limitation of Liability. In no event and under no legal theory, ++ whether in tort (including negligence), contract, or otherwise, ++ unless required by applicable law (such as deliberate and grossly ++ negligent acts) or agreed to in writing, shall any Contributor be ++ liable to You for damages, including any direct, indirect, special, ++ incidental, or consequential damages of any character arising as a ++ result of this License or out of the use or inability to use the ++ Work (including but not limited to damages for loss of goodwill, ++ work stoppage, computer failure or malfunction, or any and all ++ other commercial damages or losses), even if such Contributor ++ has been advised of the possibility of such damages. ++ ++ 9. Accepting Warranty or Additional Liability. While redistributing ++ the Work or Derivative Works thereof, You may choose to offer, ++ and charge a fee for, acceptance of support, warranty, indemnity, ++ or other liability obligations and/or rights consistent with this ++ License. However, in accepting such obligations, You may act only ++ on Your own behalf and on Your sole responsibility, not on behalf ++ of any other Contributor, and only if You agree to indemnify, ++ defend, and hold each Contributor harmless for any liability ++ incurred by, or claims asserted against, such Contributor by reason ++ of your accepting any such warranty or additional liability. ++ ++ END OF TERMS AND CONDITIONS ++ +diff --git a/media/libstagefright/codecs/raw/SoftRaw.cpp b/media/libstagefright/codecs/raw/SoftRaw.cpp +new file mode 100644 +index 0000000..82dd171 +--- /dev/null ++++ b/media/libstagefright/codecs/raw/SoftRaw.cpp +@@ -0,0 +1,281 @@ ++/* ++ * Copyright (C) 2012 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 "SoftRaw" ++#include ++ ++#include "SoftRaw.h" ++ ++#include ++#include ++ ++namespace android { ++ ++template ++static void InitOMXParams(T *params) { ++ params->nSize = sizeof(T); ++ params->nVersion.s.nVersionMajor = 1; ++ params->nVersion.s.nVersionMinor = 0; ++ params->nVersion.s.nRevision = 0; ++ params->nVersion.s.nStep = 0; ++} ++ ++SoftRaw::SoftRaw( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SimpleSoftOMXComponent(name, callbacks, appData, component), ++ mSignalledError(false), ++ mChannelCount(2), ++ mSampleRate(44100), ++ mNumericalData(OMX_NumericalDataSigned), ++ mBitsPerSample(16) { ++ initPorts(); ++ CHECK_EQ(initDecoder(), (status_t)OK); ++} ++ ++SoftRaw::~SoftRaw() { ++} ++ ++void SoftRaw::initPorts() { ++ OMX_PARAM_PORTDEFINITIONTYPE def; ++ InitOMXParams(&def); ++ ++ def.nPortIndex = 0; ++ def.eDir = OMX_DirInput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = 192 * 1024; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 1; ++ ++ def.format.audio.cMIMEType = const_cast("audio/raw"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; ++ ++ addPort(def); ++ ++ def.nPortIndex = 1; ++ def.eDir = OMX_DirOutput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = 192 * 1024; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 2; ++ ++ def.format.audio.cMIMEType = const_cast("audio/raw"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; ++ ++ addPort(def); ++} ++ ++status_t SoftRaw::initDecoder() { ++ return OK; ++} ++ ++OMX_ERRORTYPE SoftRaw::internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamAudioPortFormat: ++ { ++ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (formatParams->nIndex > 0) { ++ return OMX_ErrorNoMore; ++ } ++ ++ formatParams->eEncoding = OMX_AUDIO_CodingPCM; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 0 && pcmParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ pcmParams->eNumData = (OMX_NUMERICALDATATYPE)mNumericalData; ++ pcmParams->eEndian = OMX_EndianBig; ++ pcmParams->bInterleaved = OMX_TRUE; ++ pcmParams->nBitPerSample = mBitsPerSample; ++ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; ++ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; ++ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; ++ ++ pcmParams->nChannels = mChannelCount; ++ pcmParams->nSamplingRate = mSampleRate; ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalGetParameter(index, params); ++ } ++} ++ ++OMX_ERRORTYPE SoftRaw::internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamStandardComponentRole: ++ { ++ const OMX_PARAM_COMPONENTROLETYPE *roleParams = ++ (const OMX_PARAM_COMPONENTROLETYPE *)params; ++ ++ if (!isValidOMXParam(roleParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (strncmp((const char *)roleParams->cRole, ++ "audio_decoder.raw", ++ OMX_MAX_STRINGNAME_SIZE - 1)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPortFormat: ++ { ++ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (formatParams->eEncoding != OMX_AUDIO_CodingPCM) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ mChannelCount = pcmParams->nChannels; ++ mSampleRate = pcmParams->nSamplingRate; ++ mNumericalData = pcmParams->eNumData; ++ mBitsPerSample = pcmParams->nBitPerSample; ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ { ++ OMX_ERRORTYPE err = SimpleSoftOMXComponent::internalSetParameter( ++ index, params); ++ // In case inPort->mDef.nBufferSize changed, the output buffer size ++ // should match the input buffer size. ++ PortInfo *inPort = editPortInfo(0); ++ PortInfo *outPort = editPortInfo(1); ++ outPort->mDef.nBufferSize = inPort->mDef.nBufferSize; ++ return err; ++ } ++ } ++} ++ ++void SoftRaw::onQueueFilled(OMX_U32 /* portIndex */) { ++ if (mSignalledError) { ++ return; ++ } ++ ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ ++ while (!inQueue.empty() && !outQueue.empty()) { ++ BufferInfo *inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++ ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ ++ CHECK_GE(outHeader->nAllocLen, inHeader->nFilledLen); ++ memcpy(outHeader->pBuffer, ++ inHeader->pBuffer + inHeader->nOffset, ++ inHeader->nFilledLen); ++ ++ outHeader->nFlags = inHeader->nFlags; ++ outHeader->nOffset = 0; ++ outHeader->nFilledLen = inHeader->nFilledLen; ++ outHeader->nTimeStamp = inHeader->nTimeStamp; ++ ++ bool sawEOS = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0; ++ ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ ++ outQueue.erase(outQueue.begin()); ++ outInfo->mOwnedByUs = false; ++ notifyFillBufferDone(outHeader); ++ ++ if (sawEOS) { ++ break; ++ } ++ } ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ return new android::SoftRaw(name, callbacks, appData, component); ++} +diff --git a/media/libstagefright/codecs/raw/SoftRaw.h b/media/libstagefright/codecs/raw/SoftRaw.h +new file mode 100644 +index 0000000..ebc2741 +--- /dev/null ++++ b/media/libstagefright/codecs/raw/SoftRaw.h +@@ -0,0 +1,64 @@ ++/* ++ * Copyright (C) 2012 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 SOFT_RAW_H_ ++ ++#define SOFT_RAW_H_ ++ ++#include ++ ++struct tPVMP4AudioDecoderExternal; ++ ++namespace android { ++ ++struct SoftRaw : public SimpleSoftOMXComponent { ++ SoftRaw(const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++protected: ++ virtual ~SoftRaw(); ++ ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params); ++ ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ ++private: ++ enum { ++ kNumBuffers = 4 ++ }; ++ ++ bool mSignalledError; ++ ++ int32_t mChannelCount; ++ int32_t mSampleRate; ++ int32_t mNumericalData; ++ int32_t mBitsPerSample; ++ ++ void initPorts(); ++ status_t initDecoder(); ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftRaw); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_RAW_H_ +diff --git a/media/libstagefright/codecs/raw/exports.lds b/media/libstagefright/codecs/raw/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/raw/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/vorbis/dec/Android.bp b/media/libstagefright/codecs/vorbis/dec/Android.bp +new file mode 100644 +index 0000000..7764294 +--- /dev/null ++++ b/media/libstagefright/codecs/vorbis/dec/Android.bp +@@ -0,0 +1,38 @@ ++package { ++ default_applicable_licenses: [ ++ "frameworks_av_media_libstagefright_codecs_vorbis_dec_license", ++ ], ++} ++ ++// Added automatically by a large-scale-change ++// See: http://go/android-license-faq ++license { ++ name: "frameworks_av_media_libstagefright_codecs_vorbis_dec_license", ++ visibility: [":__subpackages__"], ++ license_kinds: [ ++ "SPDX-license-identifier-Apache-2.0", ++ ], ++ license_text: [ ++ "NOTICE", ++ ], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_vorbisdec", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: ["SoftVorbis.cpp"], ++ ++ shared_libs: [ ++ "libvorbisidec", ++ ], ++ ++ version_script: "exports.lds", ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ "unsigned-integer-overflow", ++ ], ++ }, ++} +diff --git a/media/libstagefright/codecs/vorbis/dec/MODULE_LICENSE_APACHE2 b/media/libstagefright/codecs/vorbis/dec/MODULE_LICENSE_APACHE2 +new file mode 100644 +index 0000000..e69de29 +diff --git a/media/libstagefright/codecs/vorbis/dec/NOTICE b/media/libstagefright/codecs/vorbis/dec/NOTICE +new file mode 100644 +index 0000000..c5b1efa +--- /dev/null ++++ b/media/libstagefright/codecs/vorbis/dec/NOTICE +@@ -0,0 +1,190 @@ ++ ++ Copyright (c) 2005-2008, 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. ++ ++ 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. ++ ++ ++ Apache License ++ Version 2.0, January 2004 ++ http://www.apache.org/licenses/ ++ ++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION ++ ++ 1. Definitions. ++ ++ "License" shall mean the terms and conditions for use, reproduction, ++ and distribution as defined by Sections 1 through 9 of this document. ++ ++ "Licensor" shall mean the copyright owner or entity authorized by ++ the copyright owner that is granting the License. ++ ++ "Legal Entity" shall mean the union of the acting entity and all ++ other entities that control, are controlled by, or are under common ++ control with that entity. For the purposes of this definition, ++ "control" means (i) the power, direct or indirect, to cause the ++ direction or management of such entity, whether by contract or ++ otherwise, or (ii) ownership of fifty percent (50%) or more of the ++ outstanding shares, or (iii) beneficial ownership of such entity. ++ ++ "You" (or "Your") shall mean an individual or Legal Entity ++ exercising permissions granted by this License. ++ ++ "Source" form shall mean the preferred form for making modifications, ++ including but not limited to software source code, documentation ++ source, and configuration files. ++ ++ "Object" form shall mean any form resulting from mechanical ++ transformation or translation of a Source form, including but ++ not limited to compiled object code, generated documentation, ++ and conversions to other media types. ++ ++ "Work" shall mean the work of authorship, whether in Source or ++ Object form, made available under the License, as indicated by a ++ copyright notice that is included in or attached to the work ++ (an example is provided in the Appendix below). ++ ++ "Derivative Works" shall mean any work, whether in Source or Object ++ form, that is based on (or derived from) the Work and for which the ++ editorial revisions, annotations, elaborations, or other modifications ++ represent, as a whole, an original work of authorship. For the purposes ++ of this License, Derivative Works shall not include works that remain ++ separable from, or merely link (or bind by name) to the interfaces of, ++ the Work and Derivative Works thereof. ++ ++ "Contribution" shall mean any work of authorship, including ++ the original version of the Work and any modifications or additions ++ to that Work or Derivative Works thereof, that is intentionally ++ submitted to Licensor for inclusion in the Work by the copyright owner ++ or by an individual or Legal Entity authorized to submit on behalf of ++ the copyright owner. For the purposes of this definition, "submitted" ++ means any form of electronic, verbal, or written communication sent ++ to the Licensor or its representatives, including but not limited to ++ communication on electronic mailing lists, source code control systems, ++ and issue tracking systems that are managed by, or on behalf of, the ++ Licensor for the purpose of discussing and improving the Work, but ++ excluding communication that is conspicuously marked or otherwise ++ designated in writing by the copyright owner as "Not a Contribution." ++ ++ "Contributor" shall mean Licensor and any individual or Legal Entity ++ on behalf of whom a Contribution has been received by Licensor and ++ subsequently incorporated within the Work. ++ ++ 2. Grant of Copyright License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ copyright license to reproduce, prepare Derivative Works of, ++ publicly display, publicly perform, sublicense, and distribute the ++ Work and such Derivative Works in Source or Object form. ++ ++ 3. Grant of Patent License. Subject to the terms and conditions of ++ this License, each Contributor hereby grants to You a perpetual, ++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable ++ (except as stated in this section) patent license to make, have made, ++ use, offer to sell, sell, import, and otherwise transfer the Work, ++ where such license applies only to those patent claims licensable ++ by such Contributor that are necessarily infringed by their ++ Contribution(s) alone or by combination of their Contribution(s) ++ with the Work to which such Contribution(s) was submitted. If You ++ institute patent litigation against any entity (including a ++ cross-claim or counterclaim in a lawsuit) alleging that the Work ++ or a Contribution incorporated within the Work constitutes direct ++ or contributory patent infringement, then any patent licenses ++ granted to You under this License for that Work shall terminate ++ as of the date such litigation is filed. ++ ++ 4. Redistribution. You may reproduce and distribute copies of the ++ Work or Derivative Works thereof in any medium, with or without ++ modifications, and in Source or Object form, provided that You ++ meet the following conditions: ++ ++ (a) You must give any other recipients of the Work or ++ Derivative Works a copy of this License; and ++ ++ (b) You must cause any modified files to carry prominent notices ++ stating that You changed the files; and ++ ++ (c) You must retain, in the Source form of any Derivative Works ++ that You distribute, all copyright, patent, trademark, and ++ attribution notices from the Source form of the Work, ++ excluding those notices that do not pertain to any part of ++ the Derivative Works; and ++ ++ (d) If the Work includes a "NOTICE" text file as part of its ++ distribution, then any Derivative Works that You distribute must ++ include a readable copy of the attribution notices contained ++ within such NOTICE file, excluding those notices that do not ++ pertain to any part of the Derivative Works, in at least one ++ of the following places: within a NOTICE text file distributed ++ as part of the Derivative Works; within the Source form or ++ documentation, if provided along with the Derivative Works; or, ++ within a display generated by the Derivative Works, if and ++ wherever such third-party notices normally appear. The contents ++ of the NOTICE file are for informational purposes only and ++ do not modify the License. You may add Your own attribution ++ notices within Derivative Works that You distribute, alongside ++ or as an addendum to the NOTICE text from the Work, provided ++ that such additional attribution notices cannot be construed ++ as modifying the License. ++ ++ You may add Your own copyright statement to Your modifications and ++ may provide additional or different license terms and conditions ++ for use, reproduction, or distribution of Your modifications, or ++ for any such Derivative Works as a whole, provided Your use, ++ reproduction, and distribution of the Work otherwise complies with ++ the conditions stated in this License. ++ ++ 5. Submission of Contributions. Unless You explicitly state otherwise, ++ any Contribution intentionally submitted for inclusion in the Work ++ by You to the Licensor shall be under the terms and conditions of ++ this License, without any additional terms or conditions. ++ Notwithstanding the above, nothing herein shall supersede or modify ++ the terms of any separate license agreement you may have executed ++ with Licensor regarding such Contributions. ++ ++ 6. Trademarks. This License does not grant permission to use the trade ++ names, trademarks, service marks, or product names of the Licensor, ++ except as required for reasonable and customary use in describing the ++ origin of the Work and reproducing the content of the NOTICE file. ++ ++ 7. Disclaimer of Warranty. Unless required by applicable law or ++ agreed to in writing, Licensor provides the Work (and each ++ Contributor provides its Contributions) on an "AS IS" BASIS, ++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or ++ implied, including, without limitation, any warranties or conditions ++ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A ++ PARTICULAR PURPOSE. You are solely responsible for determining the ++ appropriateness of using or redistributing the Work and assume any ++ risks associated with Your exercise of permissions under this License. ++ ++ 8. Limitation of Liability. In no event and under no legal theory, ++ whether in tort (including negligence), contract, or otherwise, ++ unless required by applicable law (such as deliberate and grossly ++ negligent acts) or agreed to in writing, shall any Contributor be ++ liable to You for damages, including any direct, indirect, special, ++ incidental, or consequential damages of any character arising as a ++ result of this License or out of the use or inability to use the ++ Work (including but not limited to damages for loss of goodwill, ++ work stoppage, computer failure or malfunction, or any and all ++ other commercial damages or losses), even if such Contributor ++ has been advised of the possibility of such damages. ++ ++ 9. Accepting Warranty or Additional Liability. While redistributing ++ the Work or Derivative Works thereof, You may choose to offer, ++ and charge a fee for, acceptance of support, warranty, indemnity, ++ or other liability obligations and/or rights consistent with this ++ License. However, in accepting such obligations, You may act only ++ on Your own behalf and on Your sole responsibility, not on behalf ++ of any other Contributor, and only if You agree to indemnify, ++ defend, and hold each Contributor harmless for any liability ++ incurred by, or claims asserted against, such Contributor by reason ++ of your accepting any such warranty or additional liability. ++ ++ END OF TERMS AND CONDITIONS ++ +diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp +new file mode 100644 +index 0000000..3daed10 +--- /dev/null ++++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp +@@ -0,0 +1,644 @@ ++/* ++ * Copyright (C) 2011 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 "SoftVorbis" ++#include ++ ++#include "SoftVorbis.h" ++ ++#include ++#include ++ ++static int kDefaultChannelCount = 1; ++static int kDefaultSamplingRate = 48000; ++ ++extern "C" { ++ #include ++ ++ int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb); ++ int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb); ++ int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb); ++} ++ ++namespace android { ++ ++template ++static void InitOMXParams(T *params) { ++ params->nSize = sizeof(T); ++ params->nVersion.s.nVersionMajor = 1; ++ params->nVersion.s.nVersionMinor = 0; ++ params->nVersion.s.nRevision = 0; ++ params->nVersion.s.nStep = 0; ++} ++ ++SoftVorbis::SoftVorbis( ++ const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component) ++ : SimpleSoftOMXComponent(name, callbacks, appData, component), ++ mInputBufferCount(0), ++ mState(NULL), ++ mVi(NULL), ++ mAnchorTimeUs(0), ++ mNumFramesOutput(0), ++ mNumFramesLeftOnPage(-1), ++ mSawInputEos(false), ++ mSignalledOutputEos(false), ++ mSignalledError(false), ++ mOutputPortSettingsChange(NONE) { ++ initPorts(); ++ CHECK_EQ(initDecoder(), (status_t)OK); ++} ++ ++SoftVorbis::~SoftVorbis() { ++ if (mState != NULL) { ++ vorbis_dsp_clear(mState); ++ delete mState; ++ mState = NULL; ++ } ++ ++ if (mVi != NULL) { ++ vorbis_info_clear(mVi); ++ delete mVi; ++ mVi = NULL; ++ } ++} ++ ++void SoftVorbis::initPorts() { ++ OMX_PARAM_PORTDEFINITIONTYPE def; ++ InitOMXParams(&def); ++ ++ def.nPortIndex = 0; ++ def.eDir = OMX_DirInput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t); ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 1; ++ ++ def.format.audio.cMIMEType = ++ const_cast(MEDIA_MIMETYPE_AUDIO_VORBIS); ++ ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingVORBIS; ++ ++ addPort(def); ++ ++ def.nPortIndex = 1; ++ def.eDir = OMX_DirOutput; ++ def.nBufferCountMin = kNumBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t); ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 2; ++ ++ def.format.audio.cMIMEType = const_cast("audio/raw"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; ++ ++ addPort(def); ++} ++ ++status_t SoftVorbis::initDecoder() { ++ return OK; ++} ++ ++OMX_ERRORTYPE SoftVorbis::internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamAudioPortFormat: ++ { ++ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (formatParams->nIndex > 0) { ++ return OMX_ErrorNoMore; ++ } ++ ++ formatParams->eEncoding = ++ (formatParams->nPortIndex == 0) ++ ? OMX_AUDIO_CodingVORBIS : OMX_AUDIO_CodingPCM; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioVorbis: ++ { ++ OMX_AUDIO_PARAM_VORBISTYPE *vorbisParams = ++ (OMX_AUDIO_PARAM_VORBISTYPE *)params; ++ ++ if (!isValidOMXParam(vorbisParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (vorbisParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ vorbisParams->nBitRate = 0; ++ vorbisParams->nMinBitRate = 0; ++ vorbisParams->nMaxBitRate = 0; ++ vorbisParams->nAudioBandWidth = 0; ++ vorbisParams->nQuality = 3; ++ vorbisParams->bManaged = OMX_FALSE; ++ vorbisParams->bDownmix = OMX_FALSE; ++ ++ if (!isConfigured()) { ++ vorbisParams->nChannels = kDefaultChannelCount; ++ vorbisParams->nSampleRate = kDefaultSamplingRate; ++ } else { ++ vorbisParams->nChannels = mVi->channels; ++ vorbisParams->nSampleRate = mVi->rate; ++ vorbisParams->nBitRate = mVi->bitrate_nominal; ++ vorbisParams->nMinBitRate = mVi->bitrate_lower; ++ vorbisParams->nMaxBitRate = mVi->bitrate_upper; ++ } ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: ++ { ++ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = ++ (OMX_AUDIO_PARAM_PCMMODETYPE *)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ pcmParams->eNumData = OMX_NumericalDataSigned; ++ pcmParams->eEndian = OMX_EndianBig; ++ pcmParams->bInterleaved = OMX_TRUE; ++ pcmParams->nBitPerSample = 16; ++ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; ++ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; ++ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; ++ ++ if (!isConfigured()) { ++ pcmParams->nChannels = kDefaultChannelCount; ++ pcmParams->nSamplingRate = kDefaultSamplingRate; ++ } else { ++ pcmParams->nChannels = mVi->channels; ++ pcmParams->nSamplingRate = mVi->rate; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalGetParameter(index, params); ++ } ++} ++ ++OMX_ERRORTYPE SoftVorbis::internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params) { ++ switch (index) { ++ case OMX_IndexParamStandardComponentRole: ++ { ++ const OMX_PARAM_COMPONENTROLETYPE *roleParams = ++ (const OMX_PARAM_COMPONENTROLETYPE *)params; ++ ++ if (!isValidOMXParam(roleParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (strncmp((const char *)roleParams->cRole, ++ "audio_decoder.vorbis", ++ OMX_MAX_STRINGNAME_SIZE - 1)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPortFormat: ++ { ++ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = ++ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if ((formatParams->nPortIndex == 0 ++ && formatParams->eEncoding != OMX_AUDIO_CodingVORBIS) ++ || (formatParams->nPortIndex == 1 ++ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioVorbis: ++ { ++ const OMX_AUDIO_PARAM_VORBISTYPE *vorbisParams = ++ (const OMX_AUDIO_PARAM_VORBISTYPE *)params; ++ ++ if (!isValidOMXParam(vorbisParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (vorbisParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalSetParameter(index, params); ++ } ++} ++ ++bool SoftVorbis::isConfigured() const { ++ return (mState != NULL && mVi != NULL); ++} ++ ++static void makeBitReader( ++ const void *data, size_t size, ++ ogg_buffer *buf, ogg_reference *ref, oggpack_buffer *bits) { ++ buf->data = (uint8_t *)data; ++ buf->size = size; ++ buf->refcount = 1; ++ buf->ptr.owner = NULL; ++ ++ ref->buffer = buf; ++ ref->begin = 0; ++ ref->length = size; ++ ref->next = NULL; ++ ++ oggpack_readinit(bits, ref); ++} ++ ++void SoftVorbis::handleEOS() { ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ ++ CHECK(!inQueue.empty() && !outQueue.empty()); ++ ++ mSawInputEos = true; ++ ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ outHeader->nFilledLen = 0; ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ ++ outQueue.erase(outQueue.begin()); ++ outInfo->mOwnedByUs = false; ++ notifyFillBufferDone(outHeader); ++ mSignalledOutputEos = true; ++ ++ BufferInfo *inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ ++mInputBufferCount; ++} ++ ++void SoftVorbis::onQueueFilled(OMX_U32 /* portIndex */) { ++ List &inQueue = getPortQueue(0); ++ List &outQueue = getPortQueue(1); ++ ++ if (mSignalledError || mOutputPortSettingsChange != NONE) { ++ return; ++ } ++ ++ while (!mSignalledOutputEos && (!inQueue.empty() || mSawInputEos) && !outQueue.empty()) { ++ BufferInfo *inInfo = NULL; ++ OMX_BUFFERHEADERTYPE *inHeader = NULL; ++ if (!inQueue.empty()) { ++ inInfo = *inQueue.begin(); ++ inHeader = inInfo->mHeader; ++ } ++ ++ BufferInfo *outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; ++ ++ int32_t numPageSamples = 0; ++ ++ if (inHeader) { ++ // Assume the very first 2 buffers are always codec config (in this case mState is NULL) ++ // After flush, handle CSD ++ if (mInputBufferCount < 2 && ++ (mState == NULL || (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG))) { ++ const uint8_t *data = inHeader->pBuffer + inHeader->nOffset; ++ size_t size = inHeader->nFilledLen; ++ ++ if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && size == 0) { ++ handleEOS(); ++ return; ++ } ++ ++ if (size < 7) { ++ ALOGE("Too small input buffer: %zu bytes", size); ++ android_errorWriteLog(0x534e4554, "27833616"); ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ ogg_buffer buf; ++ ogg_reference ref; ++ oggpack_buffer bits; ++ ++ makeBitReader((const uint8_t *)data + 7, size - 7, &buf, &ref, &bits); ++ ++ // Assume very first frame is identification header - or reset identification ++ // header after flush, but allow only specifying setup header after flush if ++ // identification header was already set up. ++ if (mInputBufferCount == 0 && ++ (mVi == NULL || data[0] == 1 /* identification header */)) { ++ // remove any prior state ++ if (mVi != NULL) { ++ // also clear mState as it may refer to the old mVi ++ if (mState != NULL) { ++ vorbis_dsp_clear(mState); ++ delete mState; ++ mState = NULL; ++ } ++ vorbis_info_clear(mVi); ++ delete mVi; ++ mVi = NULL; ++ } ++ ++ CHECK(mVi == NULL); ++ mVi = new vorbis_info; ++ vorbis_info_init(mVi); ++ ++ int ret = _vorbis_unpack_info(mVi, &bits); ++ if (ret != 0) { ++ notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL); ++ mSignalledError = true; ++ return; ++ } ++ } else { ++ // remove any prior state ++ if (mState != NULL) { ++ vorbis_dsp_clear(mState); ++ delete mState; ++ mState = NULL; ++ } ++ ++ int ret = _vorbis_unpack_books(mVi, &bits); ++ if (ret != 0 || mState != NULL) { ++ notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL); ++ mSignalledError = true; ++ return; ++ } ++ ++ CHECK(mState == NULL); ++ mState = new vorbis_dsp_state; ++ CHECK_EQ(0, vorbis_dsp_init(mState, mVi)); ++ ++ if (mVi->rate != kDefaultSamplingRate || ++ mVi->channels != kDefaultChannelCount) { ++ ALOGV("vorbis: rate/channels changed: %ld/%d", mVi->rate, mVi->channels); ++ notify(OMX_EventPortSettingsChanged, 1, 0, NULL); ++ mOutputPortSettingsChange = AWAITING_DISABLED; ++ } ++ mInputBufferCount = 1; ++ } ++ ++ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ handleEOS(); ++ return; ++ } ++ ++ inQueue.erase(inQueue.begin()); ++ inInfo->mOwnedByUs = false; ++ notifyEmptyBufferDone(inHeader); ++ ++mInputBufferCount; ++ ++ continue; ++ } ++ ++ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { ++ mSawInputEos = true; ++ } ++ ++ if (inHeader->nFilledLen || !mSawInputEos) { ++ if (inHeader->nFilledLen < sizeof(numPageSamples)) { ++ notify(OMX_EventError, OMX_ErrorBadParameter, 0, NULL); ++ mSignalledError = true; ++ ALOGE("onQueueFilled, input header has nFilledLen %u, expected %zu", ++ inHeader->nFilledLen, sizeof(numPageSamples)); ++ return; ++ } ++ memcpy(&numPageSamples, ++ inHeader->pBuffer + inHeader->nOffset + inHeader->nFilledLen - 4, ++ sizeof(numPageSamples)); ++ ++ if (inHeader->nOffset == 0) { ++ mAnchorTimeUs = inHeader->nTimeStamp; ++ mNumFramesOutput = 0; ++ } ++ ++ inHeader->nFilledLen -= sizeof(numPageSamples);; ++ } ++ } ++ ++ if (numPageSamples >= 0) { ++ mNumFramesLeftOnPage = numPageSamples; ++ } ++ ++ ogg_buffer buf; ++ buf.data = inHeader ? inHeader->pBuffer + inHeader->nOffset : NULL; ++ buf.size = inHeader ? inHeader->nFilledLen : 0; ++ buf.refcount = 1; ++ buf.ptr.owner = NULL; ++ ++ ogg_reference ref; ++ ref.buffer = &buf; ++ ref.begin = 0; ++ ref.length = buf.size; ++ ref.next = NULL; ++ ++ ogg_packet pack; ++ pack.packet = &ref; ++ pack.bytes = ref.length; ++ pack.b_o_s = 0; ++ pack.e_o_s = 0; ++ pack.granulepos = 0; ++ pack.packetno = 0; ++ ++ int numFrames = 0; ++ ++ outHeader->nFlags = 0; ++ ++ if (mState == nullptr || mVi == nullptr) { ++ notify(OMX_EventError, OMX_ErrorStreamCorrupt, 0, NULL); ++ mSignalledError = true; ++ ALOGE("onQueueFilled, input does not have CSD"); ++ return; ++ } ++ ++ int err = vorbis_dsp_synthesis(mState, &pack, 1); ++ if (err != 0) { ++ // FIXME temporary workaround for log spam ++#if !defined(__arm__) && !defined(__aarch64__) ++ ALOGV("vorbis_dsp_synthesis returned %d", err); ++#else ++ ALOGW("vorbis_dsp_synthesis returned %d", err); ++#endif ++ } else { ++ size_t numSamplesPerBuffer = kMaxNumSamplesPerBuffer; ++ if (numSamplesPerBuffer > outHeader->nAllocLen / sizeof(int16_t)) { ++ numSamplesPerBuffer = outHeader->nAllocLen / sizeof(int16_t); ++ android_errorWriteLog(0x534e4554, "27833616"); ++ } ++ numFrames = vorbis_dsp_pcmout( ++ mState, (int16_t *)outHeader->pBuffer, ++ (numSamplesPerBuffer / mVi->channels)); ++ ++ if (numFrames < 0) { ++ ALOGE("vorbis_dsp_pcmout returned %d", numFrames); ++ numFrames = 0; ++ } ++ } ++ ++ if (mNumFramesLeftOnPage >= 0) { ++ if (numFrames > mNumFramesLeftOnPage) { ++ ALOGV("discarding %d frames at end of page", ++ numFrames - mNumFramesLeftOnPage); ++ numFrames = mNumFramesLeftOnPage; ++ if (mSawInputEos) { ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ mSignalledOutputEos = true; ++ } ++ } ++ mNumFramesLeftOnPage -= numFrames; ++ } ++ ++ outHeader->nFilledLen = numFrames * sizeof(int16_t) * mVi->channels; ++ outHeader->nOffset = 0; ++ ++ outHeader->nTimeStamp = ++ mAnchorTimeUs ++ + (mNumFramesOutput * 1000000LL) / mVi->rate; ++ ++ mNumFramesOutput += numFrames; ++ ++ if (inHeader) { ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ notifyEmptyBufferDone(inHeader); ++ ++mInputBufferCount; ++ } ++ ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ notifyFillBufferDone(outHeader); ++ } ++} ++ ++void SoftVorbis::onPortFlushCompleted(OMX_U32 portIndex) { ++ if (portIndex == 0) { ++ mInputBufferCount = 0; ++ mNumFramesOutput = 0; ++ mSawInputEos = false; ++ mSignalledOutputEos = false; ++ mNumFramesLeftOnPage = -1; ++ if (mState != NULL) { ++ // Make sure that the next buffer output does not still ++ // depend on fragments from the last one decoded. ++ vorbis_dsp_restart(mState); ++ } ++ } ++} ++ ++void SoftVorbis::onReset() { ++ mInputBufferCount = 0; ++ mNumFramesOutput = 0; ++ if (mState != NULL) { ++ vorbis_dsp_clear(mState); ++ delete mState; ++ mState = NULL; ++ } ++ ++ if (mVi != NULL) { ++ vorbis_info_clear(mVi); ++ delete mVi; ++ mVi = NULL; ++ } ++ ++ mSawInputEos = false; ++ mSignalledOutputEos = false; ++ mSignalledError = false; ++ mNumFramesLeftOnPage = -1; ++ mOutputPortSettingsChange = NONE; ++} ++ ++void SoftVorbis::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { ++ if (portIndex != 1) { ++ return; ++ } ++ ++ switch (mOutputPortSettingsChange) { ++ case NONE: ++ break; ++ ++ case AWAITING_DISABLED: ++ { ++ CHECK(!enabled); ++ mOutputPortSettingsChange = AWAITING_ENABLED; ++ break; ++ } ++ ++ default: ++ { ++ CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); ++ CHECK(enabled); ++ mOutputPortSettingsChange = NONE; ++ break; ++ } ++ } ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent *createSoftOMXComponent( ++ const char *name, const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE **component) { ++ return new android::SoftVorbis(name, callbacks, appData, component); ++} +diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h +new file mode 100644 +index 0000000..5ff8ea4 +--- /dev/null ++++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h +@@ -0,0 +1,83 @@ ++/* ++ * Copyright (C) 2011 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 SOFT_VORBIS_H_ ++ ++#define SOFT_VORBIS_H_ ++ ++#include ++ ++struct vorbis_dsp_state; ++struct vorbis_info; ++ ++namespace android { ++ ++struct SoftVorbis : public SimpleSoftOMXComponent { ++ SoftVorbis(const char *name, ++ const OMX_CALLBACKTYPE *callbacks, ++ OMX_PTR appData, ++ OMX_COMPONENTTYPE **component); ++ ++protected: ++ virtual ~SoftVorbis(); ++ ++ virtual OMX_ERRORTYPE internalGetParameter( ++ OMX_INDEXTYPE index, OMX_PTR params); ++ ++ virtual OMX_ERRORTYPE internalSetParameter( ++ OMX_INDEXTYPE index, const OMX_PTR params); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ virtual void onPortFlushCompleted(OMX_U32 portIndex); ++ virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled); ++ virtual void onReset(); ++ ++private: ++ enum { ++ kNumBuffers = 4, ++ kMaxNumSamplesPerBuffer = 8192 * 2 ++ }; ++ ++ size_t mInputBufferCount; ++ ++ vorbis_dsp_state *mState; ++ vorbis_info *mVi; ++ ++ int64_t mAnchorTimeUs; ++ int64_t mNumFramesOutput; ++ int32_t mNumFramesLeftOnPage; ++ bool mSawInputEos; ++ bool mSignalledOutputEos; ++ bool mSignalledError; ++ ++ enum { ++ NONE, ++ AWAITING_DISABLED, ++ AWAITING_ENABLED ++ } mOutputPortSettingsChange; ++ ++ void initPorts(); ++ status_t initDecoder(); ++ bool isConfigured() const; ++ void handleEOS(); ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftVorbis); ++}; ++ ++} // namespace android ++ ++#endif // SOFT_VORBIS_H_ ++ +diff --git a/media/libstagefright/codecs/vorbis/dec/exports.lds b/media/libstagefright/codecs/vorbis/dec/exports.lds +new file mode 100644 +index 0000000..e24f3fa +--- /dev/null ++++ b/media/libstagefright/codecs/vorbis/dec/exports.lds +@@ -0,0 +1,5 @@ ++{ ++ global: ++ _Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE; ++ local: *; ++}; +diff --git a/media/libstagefright/codecs/xaacdec/Android.bp b/media/libstagefright/codecs/xaacdec/Android.bp +new file mode 100644 +index 0000000..1d03c16 +--- /dev/null ++++ b/media/libstagefright/codecs/xaacdec/Android.bp +@@ -0,0 +1,36 @@ ++package { ++ // See: http://go/android-license-faq ++ // A large-scale-change added 'default_applicable_licenses' to import ++ // all of the 'license_kinds' from "frameworks_av_media_libstagefright_license" ++ // to get the below license kinds: ++ // SPDX-license-identifier-Apache-2.0 ++ default_applicable_licenses: ["frameworks_av_media_libstagefright_license"], ++} ++ ++cc_library_shared { ++ name: "libstagefright_soft_xaacdec", ++ defaults: ["libstagefright_softomx-defaults"], ++ ++ srcs: [ ++ "SoftXAAC.cpp", ++ ], ++ ++ cflags: [ ++ "-DENABLE_MPEG_D_DRC" ++ ], ++ ++ sanitize: { ++ // integer_overflow: true, ++ misc_undefined: [ "signed-integer-overflow", "unsigned-integer-overflow", ], ++ cfi: true, ++ config: { ++ cfi_assembly_support: true, ++ }, ++ }, ++ ++ static_libs: ["libxaacdec"], ++ ++ shared_libs: [ ++ "libcutils", ++ ], ++} +diff --git a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp +new file mode 100644 +index 0000000..a478642 +--- /dev/null ++++ b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp +@@ -0,0 +1,1702 @@ ++/* ++ * Copyright (C) 2018 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 "SoftXAAC" ++#include ++ ++#include "SoftXAAC.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* 64*-0.25dB = -16 dB below full scale for mobile conf */ ++#define DRC_DEFAULT_MOBILE_REF_LEVEL 64 ++/* maximum compression of dynamic range for mobile conf */ ++#define DRC_DEFAULT_MOBILE_DRC_CUT 127 ++/* maximum compression of dynamic range for mobile conf */ ++#define DRC_DEFAULT_MOBILE_DRC_BOOST 127 ++/* switch for heavy compression for mobile conf */ ++#define DRC_DEFAULT_MOBILE_DRC_HEAVY 1 ++/* encoder target level; -1 => the value is unknown, ++ * otherwise dB step value (e.g. 64 for -16 dB) */ ++#define DRC_DEFAULT_MOBILE_ENC_LEVEL (-1) ++ ++/* Default Effect type is "Limited playback" */ ++#define DRC_KEY_AAC_DRC_EFFECT_TYPE (3) ++ ++/* REF_LEVEL of 64 pairs well with EFFECT_TYPE of 3. */ ++/* Default loudness value for MPEG-D DRC */ ++#define DRC_DEFAULT_MOBILE_LOUDNESS_LEVEL (64) ++ ++#define PROP_DRC_OVERRIDE_REF_LEVEL "aac_drc_reference_level" ++#define PROP_DRC_OVERRIDE_CUT "aac_drc_cut" ++#define PROP_DRC_OVERRIDE_BOOST "aac_drc_boost" ++#define PROP_DRC_OVERRIDE_HEAVY "aac_drc_heavy" ++#define PROP_DRC_OVERRIDE_ENC_LEVEL "aac_drc_enc_target_level" ++#define PROP_DRC_OVERRIDE_EFFECT_TYPE "ro.aac_drc_effect_type" ++ ++/* maximum number of audio channels that can be decoded */ ++#define MAX_CHANNEL_COUNT 8 ++ ++#define RETURN_IF_FATAL(retval, str) \ ++ if (retval & IA_FATAL_ERROR) { \ ++ ALOGE("Error in %s: Returned: %d", str, retval); \ ++ return retval; \ ++ } else if (retval != IA_NO_ERROR) { \ ++ ALOGW("Warning in %s: Returned: %d", str, retval); \ ++ } ++ ++namespace android { ++ ++template ++static void InitOMXParams(T* params) { ++ params->nSize = sizeof(T); ++ params->nVersion.s.nVersionMajor = 1; ++ params->nVersion.s.nVersionMinor = 0; ++ params->nVersion.s.nRevision = 0; ++ params->nVersion.s.nStep = 0; ++} ++ ++static const OMX_U32 kSupportedProfiles[] = { ++ OMX_AUDIO_AACObjectLC, OMX_AUDIO_AACObjectHE, OMX_AUDIO_AACObjectHE_PS, ++ OMX_AUDIO_AACObjectLD, OMX_AUDIO_AACObjectELD, OMX_AUDIO_AACObjectXHE ++}; ++ ++SoftXAAC::SoftXAAC(const char* name, const OMX_CALLBACKTYPE* callbacks, OMX_PTR appData, ++ OMX_COMPONENTTYPE** component) ++ : SimpleSoftOMXComponent(name, callbacks, appData, component), ++ mIsADTS(false), ++ mInputBufferCount(0), ++ mOutputBufferCount(0), ++ mSignalledError(false), ++ mLastInHeader(NULL), ++ mPrevTimestamp(0), ++ mCurrentTimestamp(0), ++ mOutputPortSettingsChange(NONE), ++ mXheaacCodecHandle(NULL), ++ mMpegDDrcHandle(NULL), ++ mInputBufferSize(0), ++ mOutputFrameLength(1024), ++ mInputBuffer(NULL), ++ mOutputBuffer(NULL), ++ mSampFreq(0), ++ mNumChannels(0), ++ mPcmWdSz(0), ++ mChannelMask(0), ++ mIsCodecInitialized(false), ++ mIsCodecConfigFlushRequired(false), ++ mMpegDDRCPresent(0), ++ mDRCFlag(0) ++ ++{ ++ initPorts(); ++ mMemoryVec.clear(); ++ mDrcMemoryVec.clear(); ++ ++ CHECK_EQ(initDecoder(), IA_NO_ERROR); ++} ++ ++SoftXAAC::~SoftXAAC() { ++ IA_ERRORCODE err_code = deInitXAACDecoder(); ++ if (IA_NO_ERROR != err_code) { ++ ALOGE("deInitXAACDecoder() failed %d", err_code); ++ } ++ ++ err_code = deInitMPEGDDDrc(); ++ if (IA_NO_ERROR != err_code) { ++ ALOGE("deInitMPEGDDDrc() failed %d", err_code); ++ } ++ mIsCodecInitialized = false; ++ mIsCodecConfigFlushRequired = false; ++} ++ ++void SoftXAAC::initPorts() { ++ OMX_PARAM_PORTDEFINITIONTYPE def; ++ InitOMXParams(&def); ++ ++ def.nPortIndex = 0; ++ def.eDir = OMX_DirInput; ++ def.nBufferCountMin = kNumInputBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = 8192; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 1; ++ ++ def.format.audio.cMIMEType = const_cast("audio/aac"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingAAC; ++ ++ addPort(def); ++ ++ def.nPortIndex = 1; ++ def.eDir = OMX_DirOutput; ++ def.nBufferCountMin = kNumOutputBuffers; ++ def.nBufferCountActual = def.nBufferCountMin; ++ def.nBufferSize = 4096 * MAX_CHANNEL_COUNT; ++ def.bEnabled = OMX_TRUE; ++ def.bPopulated = OMX_FALSE; ++ def.eDomain = OMX_PortDomainAudio; ++ def.bBuffersContiguous = OMX_FALSE; ++ def.nBufferAlignment = 2; ++ ++ def.format.audio.cMIMEType = const_cast("audio/raw"); ++ def.format.audio.pNativeRender = NULL; ++ def.format.audio.bFlagErrorConcealment = OMX_FALSE; ++ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; ++ ++ addPort(def); ++} ++ ++IA_ERRORCODE SoftXAAC::initDecoder() { ++ int ui_drc_val; ++ IA_ERRORCODE err_code = IA_NO_ERROR; ++ int loop = 0; ++ ++ err_code = initXAACDecoder(); ++ if (err_code != IA_NO_ERROR) { ++ ALOGE("initXAACDecoder failed with error %d", err_code); ++ deInitXAACDecoder(); ++ return err_code; ++ } ++ ++ mEndOfInput = false; ++ mEndOfOutput = false; ++ ++ char value[PROPERTY_VALUE_MAX]; ++ if (property_get(PROP_DRC_OVERRIDE_REF_LEVEL, value, NULL)) { ++ ui_drc_val = atoi(value); ++ ALOGV("AAC decoder using desired DRC target reference level of %d instead of %d", ++ ui_drc_val, DRC_DEFAULT_MOBILE_REF_LEVEL); ++ } else { ++ ui_drc_val = DRC_DEFAULT_MOBILE_REF_LEVEL; ++ } ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LEVEL, &ui_drc_val); ++ ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LEVEL"); ++#ifdef ENABLE_MPEG_D_DRC ++ /* Use ui_drc_val from PROP_DRC_OVERRIDE_REF_LEVEL or DRC_DEFAULT_MOBILE_REF_LEVEL ++ * for IA_ENHAACPLUS_DEC_DRC_TARGET_LOUDNESS too */ ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_DRC_TARGET_LOUDNESS, &ui_drc_val); ++ ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_DRC_TARGET_LOUDNESS"); ++#endif ++ ++ if (property_get(PROP_DRC_OVERRIDE_CUT, value, NULL)) { ++ ui_drc_val = atoi(value); ++ ALOGV("AAC decoder using desired DRC attenuation factor of %d instead of %d", ui_drc_val, ++ DRC_DEFAULT_MOBILE_DRC_CUT); ++ } else { ++ ui_drc_val = DRC_DEFAULT_MOBILE_DRC_CUT; ++ } ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_CUT, &ui_drc_val); ++ ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_CUT"); ++ ++ if (property_get(PROP_DRC_OVERRIDE_BOOST, value, NULL)) { ++ ui_drc_val = atoi(value); ++ ALOGV("AAC decoder using desired DRC boost factor of %d instead of %d", ui_drc_val, ++ DRC_DEFAULT_MOBILE_DRC_BOOST); ++ } else { ++ ui_drc_val = DRC_DEFAULT_MOBILE_DRC_BOOST; ++ } ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_BOOST, &ui_drc_val); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_BOOST"); ++ ++ if (property_get(PROP_DRC_OVERRIDE_HEAVY, value, NULL)) { ++ ui_drc_val = atoi(value); ++ ALOGV("AAC decoder using desired Heavy compression factor of %d instead of %d", ui_drc_val, ++ DRC_DEFAULT_MOBILE_DRC_HEAVY); ++ } else { ++ ui_drc_val = DRC_DEFAULT_MOBILE_DRC_HEAVY; ++ } ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_HEAVY_COMP, &ui_drc_val); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_HEAVY_COMP"); ++ ++#ifdef ENABLE_MPEG_D_DRC ++ if (property_get(PROP_DRC_OVERRIDE_EFFECT_TYPE, value, NULL)) { ++ ui_drc_val = atoi(value); ++ ALOGV("AAC decoder using desired DRC effect type of %d instead of %d", ui_drc_val, ++ DRC_KEY_AAC_DRC_EFFECT_TYPE); ++ } else { ++ ui_drc_val = DRC_KEY_AAC_DRC_EFFECT_TYPE; ++ } ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_DRC_EFFECT_TYPE, &ui_drc_val); ++ ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_DRC_EFFECT_TYPE"); ++ ++#endif ++ return IA_NO_ERROR; ++} ++ ++OMX_ERRORTYPE SoftXAAC::internalGetParameter(OMX_INDEXTYPE index, OMX_PTR params) { ++ switch ((OMX_U32)index) { ++ case OMX_IndexParamAudioPortFormat: { ++ OMX_AUDIO_PARAM_PORTFORMATTYPE* formatParams = (OMX_AUDIO_PARAM_PORTFORMATTYPE*)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (formatParams->nIndex > 0) { ++ return OMX_ErrorNoMore; ++ } ++ ++ formatParams->eEncoding = ++ (formatParams->nPortIndex == 0) ? OMX_AUDIO_CodingAAC : OMX_AUDIO_CodingPCM; ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioAac: { ++ OMX_AUDIO_PARAM_AACPROFILETYPE* aacParams = (OMX_AUDIO_PARAM_AACPROFILETYPE*)params; ++ ++ if (!isValidOMXParam(aacParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (aacParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ aacParams->nBitRate = 0; ++ aacParams->nAudioBandWidth = 0; ++ aacParams->nAACtools = 0; ++ aacParams->nAACERtools = 0; ++ aacParams->eAACProfile = OMX_AUDIO_AACObjectMain; ++ ++ aacParams->eAACStreamFormat = ++ mIsADTS ? OMX_AUDIO_AACStreamFormatMP4ADTS : OMX_AUDIO_AACStreamFormatMP4FF; ++ ++ aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo; ++ ++ if (!isConfigured()) { ++ aacParams->nChannels = 1; ++ aacParams->nSampleRate = 44100; ++ aacParams->nFrameLength = 0; ++ } else { ++ aacParams->nChannels = mNumChannels; ++ aacParams->nSampleRate = mSampFreq; ++ aacParams->nFrameLength = mOutputFrameLength; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: { ++ OMX_AUDIO_PARAM_PCMMODETYPE* pcmParams = (OMX_AUDIO_PARAM_PCMMODETYPE*)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ pcmParams->eNumData = OMX_NumericalDataSigned; ++ pcmParams->eEndian = OMX_EndianBig; ++ pcmParams->bInterleaved = OMX_TRUE; ++ pcmParams->nBitPerSample = 16; ++ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; ++ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; ++ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; ++ pcmParams->eChannelMapping[2] = OMX_AUDIO_ChannelCF; ++ pcmParams->eChannelMapping[3] = OMX_AUDIO_ChannelLFE; ++ pcmParams->eChannelMapping[4] = OMX_AUDIO_ChannelLS; ++ pcmParams->eChannelMapping[5] = OMX_AUDIO_ChannelRS; ++ ++ if (!isConfigured()) { ++ pcmParams->nChannels = 1; ++ pcmParams->nSamplingRate = 44100; ++ } else { ++ pcmParams->nChannels = mNumChannels; ++ pcmParams->nSamplingRate = mSampFreq; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioProfileQuerySupported: { ++ OMX_AUDIO_PARAM_ANDROID_PROFILETYPE* profileParams = ++ (OMX_AUDIO_PARAM_ANDROID_PROFILETYPE*)params; ++ ++ if (!isValidOMXParam(profileParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (profileParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (profileParams->nProfileIndex >= NELEM(kSupportedProfiles)) { ++ return OMX_ErrorNoMore; ++ } ++ ++ profileParams->eProfile = kSupportedProfiles[profileParams->nProfileIndex]; ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalGetParameter(index, params); ++ } ++} ++ ++OMX_ERRORTYPE SoftXAAC::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) { ++ switch ((int)index) { ++ case OMX_IndexParamStandardComponentRole: { ++ const OMX_PARAM_COMPONENTROLETYPE* roleParams = ++ (const OMX_PARAM_COMPONENTROLETYPE*)params; ++ ++ if (!isValidOMXParam(roleParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (strncmp((const char*)roleParams->cRole, "audio_decoder.aac", ++ OMX_MAX_STRINGNAME_SIZE - 1)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPortFormat: { ++ const OMX_AUDIO_PARAM_PORTFORMATTYPE* formatParams = ++ (const OMX_AUDIO_PARAM_PORTFORMATTYPE*)params; ++ ++ if (!isValidOMXParam(formatParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (formatParams->nPortIndex > 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if ((formatParams->nPortIndex == 0 && formatParams->eEncoding != OMX_AUDIO_CodingAAC) || ++ (formatParams->nPortIndex == 1 && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioAac: { ++ const OMX_AUDIO_PARAM_AACPROFILETYPE* aacParams = ++ (const OMX_AUDIO_PARAM_AACPROFILETYPE*)params; ++ ++ if (!isValidOMXParam(aacParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (aacParams->nPortIndex != 0) { ++ return OMX_ErrorUndefined; ++ } ++ ++ if (aacParams->eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4FF) { ++ mIsADTS = false; ++ } else if (aacParams->eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4ADTS) { ++ mIsADTS = true; ++ } else { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioAndroidAacDrcPresentation: { ++ const OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE* aacPresParams = ++ (const OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE*)params; ++ ++ if (!isValidOMXParam(aacPresParams)) { ++ ALOGE("set OMX_ErrorBadParameter"); ++ return OMX_ErrorBadParameter; ++ } ++ ++ // for the following parameters of the OMX_AUDIO_PARAM_AACPROFILETYPE structure, ++ // a value of -1 implies the parameter is not set by the application: ++ // nMaxOutputChannels -1 by default ++ // nDrcCut uses default platform properties, see initDecoder() ++ // nDrcBoost idem ++ // nHeavyCompression idem ++ // nTargetReferenceLevel idem ++ // nEncodedTargetLevel idem ++ if (aacPresParams->nMaxOutputChannels >= 0) { ++ int max; ++ if (aacPresParams->nMaxOutputChannels >= 8) { ++ max = 8; ++ } else if (aacPresParams->nMaxOutputChannels >= 6) { ++ max = 6; ++ } else if (aacPresParams->nMaxOutputChannels >= 2) { ++ max = 2; ++ } else { ++ // -1 or 0: disable downmix, 1: mono ++ max = aacPresParams->nMaxOutputChannels; ++ } ++ } ++ /* Apply DRC Changes */ ++ IA_ERRORCODE err_code = setXAACDRCInfo(aacPresParams->nDrcCut, aacPresParams->nDrcBoost, ++ aacPresParams->nTargetReferenceLevel, ++ aacPresParams->nHeavyCompression ++#ifdef ENABLE_MPEG_D_DRC ++ , ++ aacPresParams->nDrcEffectType ++#endif ++ ); // TOD0 : Revert this change ++ if (err_code != IA_NO_ERROR) { ++ ALOGE("Error in OMX_IndexParamAudioAndroidAacDrcPresentation"); ++ return OMX_ErrorBadParameter; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ case OMX_IndexParamAudioPcm: { ++ const OMX_AUDIO_PARAM_PCMMODETYPE* pcmParams = (OMX_AUDIO_PARAM_PCMMODETYPE*)params; ++ ++ if (!isValidOMXParam(pcmParams)) { ++ return OMX_ErrorBadParameter; ++ } ++ ++ if (pcmParams->nPortIndex != 1) { ++ return OMX_ErrorUndefined; ++ } ++ ++ return OMX_ErrorNone; ++ } ++ ++ default: ++ return SimpleSoftOMXComponent::internalSetParameter(index, params); ++ } ++} ++ ++bool SoftXAAC::isConfigured() const { ++ return mInputBufferCount > 0; ++} ++ ++void SoftXAAC::onQueueFilled(OMX_U32 /* portIndex */) { ++ if (mSignalledError || mOutputPortSettingsChange != NONE) { ++ ALOGE("onQueueFilled do not process %d %d", mSignalledError, mOutputPortSettingsChange); ++ return; ++ } ++ ++ uint8_t* inBuffer = NULL; ++ uint32_t inBufferLength = 0; ++ ++ List& inQueue = getPortQueue(0); ++ List& outQueue = getPortQueue(1); ++ ++ signed int numOutBytes = 0; ++ ++ /* If decoder call fails in between, then mOutputFrameLength is used */ ++ /* Decoded output for AAC is 1024/2048 samples / channel */ ++ /* TODO: For USAC mOutputFrameLength can go up to 4096 */ ++ /* Note: entire buffer logic to save and retrieve assumes 2 bytes per*/ ++ /* sample currently */ ++ if (mIsCodecInitialized) { ++ numOutBytes = mOutputFrameLength * (mPcmWdSz / 8) * mNumChannels; ++ } ++ ++ while ((!inQueue.empty() || mEndOfInput) && !outQueue.empty()) { ++ if (!inQueue.empty()) { ++ BufferInfo* inInfo = *inQueue.begin(); ++ OMX_BUFFERHEADERTYPE* inHeader = inInfo->mHeader; ++ ++ /* No need to check inHeader != NULL, as inQueue is not empty */ ++ mEndOfInput = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0; ++ ++ if (mInputBufferCount == 0 && !(inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) { ++ ALOGW("first buffer should have OMX_BUFFERFLAG_CODECCONFIG set"); ++ inHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG; ++ } ++ if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) != 0) { ++ inBuffer = inHeader->pBuffer + inHeader->nOffset; ++ inBufferLength = inHeader->nFilledLen; ++ ++ /* GA header configuration sent to Decoder! */ ++ IA_ERRORCODE err_code = configXAACDecoder(inBuffer, inBufferLength); ++ if (IA_NO_ERROR != err_code) { ++ ALOGW("configXAACDecoder err_code = %d", err_code); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, err_code, NULL); ++ return; ++ } ++ mInputBufferCount++; ++ mOutputBufferCount++; // fake increase of outputBufferCount to keep the counters ++ // aligned ++ ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ mLastInHeader = NULL; ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ ++ // Only send out port settings changed event if both sample rate ++ // and mNumChannels are valid. ++ if (mSampFreq && mNumChannels && !mIsCodecConfigFlushRequired) { ++ ALOGV("Configuring decoder: %d Hz, %d channels", mSampFreq, mNumChannels); ++ notify(OMX_EventPortSettingsChanged, 1, 0, NULL); ++ mOutputPortSettingsChange = AWAITING_DISABLED; ++ } ++ ++ return; ++ } ++ ++ if (inHeader->nFilledLen == 0) { ++ inInfo->mOwnedByUs = false; ++ inQueue.erase(inQueue.begin()); ++ mLastInHeader = NULL; ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ continue; ++ } ++ ++ // Restore Offset and Length for Port reconfig case ++ size_t tempOffset = inHeader->nOffset; ++ size_t tempFilledLen = inHeader->nFilledLen; ++ if (mIsADTS) { ++ size_t adtsHeaderSize = 0; ++ // skip 30 bits, aac_frame_length follows. ++ // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll????? ++ ++ const uint8_t* adtsHeader = inHeader->pBuffer + inHeader->nOffset; ++ ++ bool signalError = false; ++ if (inHeader->nFilledLen < 7) { ++ ALOGE( ++ "Audio data too short to contain even the ADTS header. " ++ "Got %d bytes.", ++ inHeader->nFilledLen); ++ hexdump(adtsHeader, inHeader->nFilledLen); ++ signalError = true; ++ } else { ++ bool protectionAbsent = (adtsHeader[1] & 1); ++ ++ unsigned aac_frame_length = ++ ((adtsHeader[3] & 3) << 11) | (adtsHeader[4] << 3) | (adtsHeader[5] >> 5); ++ ++ if (inHeader->nFilledLen < aac_frame_length) { ++ ALOGE( ++ "Not enough audio data for the complete frame. " ++ "Got %d bytes, frame size according to the ADTS " ++ "header is %u bytes.", ++ inHeader->nFilledLen, aac_frame_length); ++ hexdump(adtsHeader, inHeader->nFilledLen); ++ signalError = true; ++ } else { ++ adtsHeaderSize = (protectionAbsent ? 7 : 9); ++ if (aac_frame_length < adtsHeaderSize) { ++ signalError = true; ++ } else { ++ inBuffer = (uint8_t*)adtsHeader + adtsHeaderSize; ++ inBufferLength = aac_frame_length - adtsHeaderSize; ++ ++ inHeader->nOffset += adtsHeaderSize; ++ inHeader->nFilledLen -= adtsHeaderSize; ++ } ++ } ++ } ++ ++ if (signalError) { ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorStreamCorrupt, ERROR_MALFORMED, NULL); ++ return; ++ } ++ ++ // insert buffer size and time stamp ++ if (mLastInHeader != inHeader) { ++ mCurrentTimestamp = inHeader->nTimeStamp; ++ mLastInHeader = inHeader; ++ } else { ++ mCurrentTimestamp = mPrevTimestamp + mOutputFrameLength * 1000000LL / mSampFreq; ++ } ++ } else { ++ inBuffer = inHeader->pBuffer + inHeader->nOffset; ++ inBufferLength = inHeader->nFilledLen; ++ mLastInHeader = inHeader; ++ mCurrentTimestamp = inHeader->nTimeStamp; ++ } ++ ++ int numLoops = 0; ++ signed int prevSampleRate = mSampFreq; ++ signed int prevNumChannels = mNumChannels; ++ ++ /* XAAC decoder expects first frame to be fed via configXAACDecoder API */ ++ /* which should initialize the codec. Once this state is reached, call the */ ++ /* decodeXAACStream API with same frame to decode! */ ++ if (!mIsCodecInitialized) { ++ IA_ERRORCODE err_code = configXAACDecoder(inBuffer, inBufferLength); ++ if (IA_NO_ERROR != err_code) { ++ ALOGW("configXAACDecoder Failed 2 err_code = %d", err_code); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, err_code, NULL); ++ return; ++ } ++ } ++ ++ if (!mSampFreq || !mNumChannels) { ++ if ((mInputBufferCount > 2) && (mOutputBufferCount <= 1)) { ++ ALOGW("Invalid AAC stream"); ++ ALOGW("mSampFreq %d mNumChannels %d ", mSampFreq, mNumChannels); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ } else if ((mSampFreq != prevSampleRate) || (mNumChannels != prevNumChannels)) { ++ ALOGV("Reconfiguring decoder: %d->%d Hz, %d->%d channels", prevSampleRate, ++ mSampFreq, prevNumChannels, mNumChannels); ++ inHeader->nOffset = tempOffset; ++ inHeader->nFilledLen = tempFilledLen; ++ notify(OMX_EventPortSettingsChanged, 1, 0, NULL); ++ mOutputPortSettingsChange = AWAITING_DISABLED; ++ return; ++ } ++ ++ signed int bytesConsumed = 0; ++ int errorCode = 0; ++ if (mIsCodecInitialized) { ++ mIsCodecConfigFlushRequired = true; ++ errorCode = ++ decodeXAACStream(inBuffer, inBufferLength, &bytesConsumed, &numOutBytes); ++ } else if (!mIsCodecConfigFlushRequired) { ++ ALOGW("Assumption that first frame after header initializes decoder failed!"); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, -1, NULL); ++ return; ++ } ++ inHeader->nFilledLen -= bytesConsumed; ++ inHeader->nOffset += bytesConsumed; ++ ++ if (inHeader->nFilledLen != 0) { ++ ALOGE("All data not consumed"); ++ } ++ ++ /* In case of error, decoder would have given out empty buffer */ ++ if ((0 != errorCode) && (0 == numOutBytes) && mIsCodecInitialized) { ++ numOutBytes = mOutputFrameLength * (mPcmWdSz / 8) * mNumChannels; ++ } ++ numLoops++; ++ ++ if (0 == bytesConsumed) { ++ ALOGW("bytesConsumed is zero"); ++ } ++ ++ if (errorCode) { ++ /* Clear buffer for output buffer is done inside XAAC codec */ ++ /* TODO - Check if below memset is on top of reset inside codec */ ++ memset(mOutputBuffer, 0, numOutBytes); // TODO: check for overflow, ASAN ++ // Discard input buffer. ++ inHeader->nFilledLen = 0; ++ // fall through ++ } ++ ++ if (inHeader->nFilledLen == 0) { ++ inInfo->mOwnedByUs = false; ++ mInputBufferCount++; ++ inQueue.erase(inQueue.begin()); ++ mLastInHeader = NULL; ++ inInfo = NULL; ++ notifyEmptyBufferDone(inHeader); ++ inHeader = NULL; ++ } else { ++ ALOGV("inHeader->nFilledLen = %d", inHeader->nFilledLen); ++ } ++ ++ if (!outQueue.empty() && numOutBytes) { ++ BufferInfo* outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE* outHeader = outInfo->mHeader; ++ ++ if (outHeader->nOffset != 0) { ++ ALOGE("outHeader->nOffset != 0 is not handled"); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ ++ signed short* outBuffer = ++ reinterpret_cast(outHeader->pBuffer + outHeader->nOffset); ++ int samplesize = mNumChannels * sizeof(int16_t); ++ if (outHeader->nOffset + mOutputFrameLength * samplesize > outHeader->nAllocLen) { ++ ALOGE("buffer overflow"); ++ mSignalledError = true; ++ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); ++ return; ++ } ++ memcpy(outBuffer, mOutputBuffer, numOutBytes); ++ outHeader->nFilledLen = numOutBytes; ++ ++ if (mEndOfInput && !outQueue.empty()) { ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ mEndOfOutput = true; ++ } else { ++ outHeader->nFlags = 0; ++ } ++ outHeader->nTimeStamp = mCurrentTimestamp; ++ mPrevTimestamp = mCurrentTimestamp; ++ ++ mOutputBufferCount++; ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ outInfo = NULL; ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ } ++ } ++ ++ if (mEndOfInput) { ++ if (!outQueue.empty()) { ++ if (!mEndOfOutput) { ++ ALOGV(" empty block signaling EOS"); ++ // send partial or empty block signaling EOS ++ mEndOfOutput = true; ++ BufferInfo* outInfo = *outQueue.begin(); ++ OMX_BUFFERHEADERTYPE* outHeader = outInfo->mHeader; ++ ++ outHeader->nFilledLen = 0; ++ outHeader->nFlags = OMX_BUFFERFLAG_EOS; ++ outHeader->nTimeStamp = mPrevTimestamp; ++ ++ mOutputBufferCount++; ++ outInfo->mOwnedByUs = false; ++ outQueue.erase(outQueue.begin()); ++ outInfo = NULL; ++ notifyFillBufferDone(outHeader); ++ outHeader = NULL; ++ } ++ break; // if outQueue not empty but no more output ++ } ++ } ++ } ++} ++ ++void SoftXAAC::onPortFlushCompleted(OMX_U32 portIndex) { ++ if (portIndex == 0) { ++ // Make sure that the next buffer output does not still ++ // depend on fragments from the last one decoded. ++ // drain all existing data ++ if (mIsCodecInitialized) { ++ IA_ERRORCODE err_code = configflushDecode(); ++ if (err_code != IA_NO_ERROR) { ++ ALOGE("Error in configflushDecode: Error %d", err_code); ++ } ++ } ++ drainDecoder(); ++ mLastInHeader = NULL; ++ mEndOfInput = false; ++ } else { ++ mEndOfOutput = false; ++ } ++} ++ ++IA_ERRORCODE SoftXAAC::configflushDecode() { ++ IA_ERRORCODE err_code; ++ UWORD32 ui_init_done; ++ uint32_t inBufferLength = 8203; ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT, IA_CMD_TYPE_FLUSH_MEM, NULL); ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_FLUSH_MEM"); ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_INPUT_BYTES, 0, &inBufferLength); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES"); ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT, IA_CMD_TYPE_FLUSH_MEM, NULL); ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_FLUSH_MEM"); ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_DONE_QUERY, ++ &ui_init_done); ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_DONE_QUERY"); ++ ++ if (ui_init_done) { ++ err_code = getXAACStreamInfo(); ++ RETURN_IF_FATAL(err_code, "getXAACStreamInfo"); ++ ++ ALOGV( ++ "Found Codec with below config---\nsampFreq %d\nnumChannels %d\npcmWdSz " ++ "%d\nchannelMask %d\noutputFrameLength %d", ++ mSampFreq, mNumChannels, mPcmWdSz, mChannelMask, mOutputFrameLength); ++ ++ mIsCodecInitialized = true; ++ } ++ return IA_NO_ERROR; ++} ++IA_ERRORCODE SoftXAAC::drainDecoder() { ++ return IA_NO_ERROR; ++} ++ ++void SoftXAAC::onReset() { ++ drainDecoder(); ++ ++ // reset the "configured" state ++ mInputBufferCount = 0; ++ mOutputBufferCount = 0; ++ mEndOfInput = false; ++ mEndOfOutput = false; ++ mLastInHeader = NULL; ++ ++ mSignalledError = false; ++ mOutputPortSettingsChange = NONE; ++} ++ ++void SoftXAAC::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { ++ if (portIndex != 1) { ++ return; ++ } ++ ++ switch (mOutputPortSettingsChange) { ++ case NONE: ++ break; ++ ++ case AWAITING_DISABLED: { ++ CHECK(!enabled); ++ mOutputPortSettingsChange = AWAITING_ENABLED; ++ break; ++ } ++ ++ default: { ++ CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); ++ CHECK(enabled); ++ mOutputPortSettingsChange = NONE; ++ break; ++ } ++ } ++} ++ ++IA_ERRORCODE SoftXAAC::initXAACDecoder() { ++ LOOPIDX i; ++ ++ /* Error code */ ++ IA_ERRORCODE err_code = IA_NO_ERROR; ++ ++ /* First part */ ++ /* Error Handler Init */ ++ /* Get Library Name, Library Version and API Version */ ++ /* Initialize API structure + Default config set */ ++ /* Set config params from user */ ++ /* Initialize memory tables */ ++ /* Get memory information and allocate memory */ ++ ++ /* Memory variables */ ++ UWORD32 ui_proc_mem_tabs_size; ++ /* API size */ ++ UWORD32 pui_api_size; ++ pVOID pv_alloc_ptr; ++ ++ mInputBufferSize = 0; ++ mInputBuffer = 0; ++ mOutputBuffer = 0; ++ ++ /* Process struct initing end */ ++ /* ******************************************************************/ ++ /* Initialize API structure and set config params to default */ ++ /* ******************************************************************/ ++ ++ /* Get the API size */ ++ err_code = ixheaacd_dec_api(NULL, IA_API_CMD_GET_API_SIZE, 0, &pui_api_size); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_API_SIZE"); ++ ++ /* Allocate memory for API */ ++ mXheaacCodecHandle = memalign(4, pui_api_size); ++ if (mXheaacCodecHandle == NULL) { ++ ALOGE("malloc for pui_api_size + 4 >> %d Failed", pui_api_size + 4); ++ return IA_FATAL_ERROR; ++ } ++ mMemoryVec.push(mXheaacCodecHandle); ++ ++ /* Set the config params to default values */ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT, ++ IA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, NULL); ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS"); ++#ifdef ENABLE_MPEG_D_DRC ++ /* Get the API size */ ++ err_code = ia_drc_dec_api(NULL, IA_API_CMD_GET_API_SIZE, 0, &pui_api_size); ++ ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_API_SIZE"); ++ ++ /* Allocate memory for API */ ++ mMpegDDrcHandle = memalign(4, pui_api_size); ++ ++ if (mMpegDDrcHandle == NULL) { ++ ALOGE("malloc for drc api structure Failed"); ++ return IA_FATAL_ERROR; ++ } ++ mMemoryVec.push(mMpegDDrcHandle); ++ ++ memset(mMpegDDrcHandle, 0, pui_api_size); ++ ++ /* Set the config params to default values */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, ++ IA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, NULL); ++ ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS"); ++#endif ++ ++ /* ******************************************************************/ ++ /* Set config parameters */ ++ /* ******************************************************************/ ++ UWORD32 ui_mp4_flag = 1; ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_ISMP4, &ui_mp4_flag); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_ISMP4"); ++ ++ /* ******************************************************************/ ++ /* Initialize Memory info tables */ ++ /* ******************************************************************/ ++ ++ /* Get memory info tables size */ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_MEMTABS_SIZE, 0, ++ &ui_proc_mem_tabs_size); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEMTABS_SIZE"); ++ ++ pv_alloc_ptr = memalign(4, ui_proc_mem_tabs_size); ++ if (pv_alloc_ptr == NULL) { ++ ALOGE("Malloc for size (ui_proc_mem_tabs_size + 4) = %d failed!", ++ ui_proc_mem_tabs_size + 4); ++ return IA_FATAL_ERROR; ++ } ++ mMemoryVec.push(pv_alloc_ptr); ++ ++ /* Set pointer for process memory tables */ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_MEMTABS_PTR, 0, pv_alloc_ptr); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEMTABS_PTR"); ++ ++ /* initialize the API, post config, fill memory tables */ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT, ++ IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS, NULL); ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS"); ++ ++ /* ******************************************************************/ ++ /* Allocate Memory with info from library */ ++ /* ******************************************************************/ ++ /* There are four different types of memories, that needs to be allocated */ ++ /* persistent,scratch,input and output */ ++ for (i = 0; i < 4; i++) { ++ int ui_size = 0, ui_alignment = 0, ui_type = 0; ++ pVOID pv_alloc_ptr; ++ ++ /* Get memory size */ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_MEM_INFO_SIZE, i, &ui_size); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_SIZE"); ++ ++ /* Get memory alignment */ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_MEM_INFO_ALIGNMENT, i, ++ &ui_alignment); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_ALIGNMENT"); ++ ++ /* Get memory type */ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_MEM_INFO_TYPE, i, &ui_type); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_TYPE"); ++ ++ pv_alloc_ptr = memalign(ui_alignment, ui_size); ++ if (pv_alloc_ptr == NULL) { ++ ALOGE("Malloc for size (ui_size + ui_alignment) = %d failed!", ui_size + ui_alignment); ++ return IA_FATAL_ERROR; ++ } ++ mMemoryVec.push(pv_alloc_ptr); ++ ++ /* Set the buffer pointer */ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_MEM_PTR, i, pv_alloc_ptr); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEM_PTR"); ++ if (ui_type == IA_MEMTYPE_INPUT) { ++ mInputBuffer = (pWORD8)pv_alloc_ptr; ++ mInputBufferSize = ui_size; ++ } ++ ++ if (ui_type == IA_MEMTYPE_OUTPUT) { ++ mOutputBuffer = (pWORD8)pv_alloc_ptr; ++ } ++ } ++ /* End first part */ ++ ++ return IA_NO_ERROR; ++} ++ ++IA_ERRORCODE SoftXAAC::configXAACDecoder(uint8_t* inBuffer, uint32_t inBufferLength) { ++ UWORD32 ui_init_done; ++ int32_t i_bytes_consumed; ++ ++ if (mInputBufferSize < inBufferLength) { ++ ALOGE("Cannot config AAC, input buffer size %d < inBufferLength %d", mInputBufferSize, ++ inBufferLength); ++ return false; ++ } ++ ++ /* Copy the buffer passed by Android plugin to codec input buffer */ ++ memcpy(mInputBuffer, inBuffer, inBufferLength); ++ ++ /* Set number of bytes to be processed */ ++ IA_ERRORCODE err_code = ++ ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_INPUT_BYTES, 0, &inBufferLength); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES"); ++ ++ if (mIsCodecConfigFlushRequired) { ++ /* If codec is already initialized, then GA header is passed again */ ++ /* Need to call the Flush API instead of INIT_PROCESS */ ++ mIsCodecInitialized = false; /* Codec needs to be Reinitialized after flush */ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT, IA_CMD_TYPE_GA_HDR, NULL); ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_GA_HDR"); ++ } else { ++ /* Initialize the process */ ++ err_code = ++ ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_PROCESS, NULL); ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_PROCESS"); ++ } ++ ++ /* Checking for end of initialization */ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_DONE_QUERY, ++ &ui_init_done); ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_DONE_QUERY"); ++ ++ /* How much buffer is used in input buffers */ ++ err_code = ++ ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CURIDX_INPUT_BUF, 0, &i_bytes_consumed); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_CURIDX_INPUT_BUF"); ++ ++ if (ui_init_done) { ++ err_code = getXAACStreamInfo(); ++ RETURN_IF_FATAL(err_code, "getXAACStreamInfo"); ++ ++ ALOGI( ++ "Found Codec with below config---\nsampFreq %d\nnumChannels %d\npcmWdSz " ++ "%d\nchannelMask %d\noutputFrameLength %d", ++ mSampFreq, mNumChannels, mPcmWdSz, mChannelMask, mOutputFrameLength); ++ mIsCodecInitialized = true; ++ ++#ifdef ENABLE_MPEG_D_DRC ++ err_code = configMPEGDDrc(); ++ RETURN_IF_FATAL(err_code, "configMPEGDDrc"); ++#endif ++ } ++ ++ return IA_NO_ERROR; ++} ++IA_ERRORCODE SoftXAAC::initMPEGDDDrc() { ++ IA_ERRORCODE err_code = IA_NO_ERROR; ++ int i; ++ ++ for (i = 0; i < (WORD32)2; i++) { ++ WORD32 ui_size, ui_alignment, ui_type; ++ pVOID pv_alloc_ptr; ++ ++ /* Get memory size */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_MEM_INFO_SIZE, i, &ui_size); ++ ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_SIZE"); ++ ++ /* Get memory alignment */ ++ err_code = ++ ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_MEM_INFO_ALIGNMENT, i, &ui_alignment); ++ ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_ALIGNMENT"); ++ ++ /* Get memory type */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_MEM_INFO_TYPE, i, &ui_type); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_TYPE"); ++ ++ pv_alloc_ptr = memalign(4, ui_size); ++ if (pv_alloc_ptr == NULL) { ++ ALOGE(" Cannot create requested memory %d", ui_size); ++ return IA_FATAL_ERROR; ++ } ++ mDrcMemoryVec.push(pv_alloc_ptr); ++ ++ /* Set the buffer pointer */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_MEM_PTR, i, pv_alloc_ptr); ++ ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEM_PTR"); ++ } ++ ++ WORD32 ui_size; ++ ui_size = 8192 * 2; ++ ++ mDrcInBuf = (int8_t*)memalign(4, ui_size); ++ if (mDrcInBuf == NULL) { ++ ALOGE(" Cannot create requested memory %d", ui_size); ++ return IA_FATAL_ERROR; ++ } ++ mDrcMemoryVec.push(mDrcInBuf); ++ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_MEM_PTR, 2, mDrcInBuf); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEM_PTR"); ++ ++ mDrcOutBuf = (int8_t*)memalign(4, ui_size); ++ if (mDrcOutBuf == NULL) { ++ ALOGE(" Cannot create requested memory %d", ui_size); ++ return IA_FATAL_ERROR; ++ } ++ mDrcMemoryVec.push(mDrcOutBuf); ++ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_MEM_PTR, 3, mDrcOutBuf); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEM_PTR"); ++ ++ return IA_NO_ERROR; ++} ++IA_ERRORCODE SoftXAAC::configMPEGDDrc() { ++ IA_ERRORCODE err_code = IA_NO_ERROR; ++ int i_effect_type; ++ int i_loud_norm; ++ int i_target_loudness; ++ unsigned int i_sbr_mode; ++ int i; ++ int ui_proc_mem_tabs_size = 0; ++ pVOID pv_alloc_ptr = NULL; ++ ++#ifdef ENABLE_MPEG_D_DRC ++ { ++ /* Sampling Frequency */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_DRC_DEC_CONFIG_PARAM_SAMP_FREQ, &mSampFreq); ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_SAMP_FREQ"); ++ /* Total Number of Channels */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_DRC_DEC_CONFIG_PARAM_NUM_CHANNELS, &mNumChannels); ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_NUM_CHANNELS"); ++ ++ /* PCM word size */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_DRC_DEC_CONFIG_PARAM_PCM_WDSZ, &mPcmWdSz); ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_PCM_WDSZ"); ++ ++ /*Set Effect Type*/ ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_EFFECT_TYPE, &i_effect_type); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_EFFECT_TYPE"); ++ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_DRC_DEC_CONFIG_DRC_EFFECT_TYPE, &i_effect_type); ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_DRC_EFFECT_TYPE"); ++ ++ /*Set target loudness */ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LOUDNESS, ++ &i_target_loudness); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LOUDNESS"); ++ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_DRC_DEC_CONFIG_DRC_TARGET_LOUDNESS, &i_target_loudness); ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_DRC_TARGET_LOUDNESS"); ++ ++ /*Set loud_norm_flag*/ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_LOUD_NORM, &i_loud_norm); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_LOUD_NORM"); ++ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_DRC_DEC_CONFIG_DRC_LOUD_NORM, &i_loud_norm); ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_DRC_LOUD_NORM"); ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_SBR_MODE, &i_sbr_mode); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_SBR_MODE"); ++ ++ /* Get memory info tables size */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_MEMTABS_SIZE, 0, ++ &ui_proc_mem_tabs_size); ++ ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEMTABS_SIZE"); ++ ++ pv_alloc_ptr = memalign(4, ui_proc_mem_tabs_size); ++ ++ if (pv_alloc_ptr == NULL) { ++ ALOGE("Cannot create requested memory %d", ui_proc_mem_tabs_size); ++ return IA_FATAL_ERROR; ++ } ++ ++ memset(pv_alloc_ptr, 0, ui_proc_mem_tabs_size); ++ ++ mMemoryVec.push(pv_alloc_ptr); ++ ++ /* Set pointer for process memory tables */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_MEMTABS_PTR, 0, ++ pv_alloc_ptr); ++ ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEMTABS_PTR"); ++ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, ++ IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS, NULL); ++ ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS"); ++ ++ /* Free any memory that is allocated for MPEG D Drc so far */ ++ deInitMPEGDDDrc(); ++ ++ err_code = initMPEGDDDrc(); ++ if (err_code != IA_NO_ERROR) { ++ ALOGE("initMPEGDDDrc failed with error %d", err_code); ++ deInitMPEGDDDrc(); ++ return err_code; ++ } ++ ++ /* DRC buffers ++ buf[0] - contains extension element pay load loudness related ++ buf[1] - contains extension element pay load*/ ++ { ++ VOID* p_array[2][16]; ++ WORD32 ii; ++ WORD32 buf_sizes[2][16]; ++ WORD32 num_elements; ++ WORD32 num_config_ext; ++ WORD32 bit_str_fmt = 1; ++ ++ WORD32 uo_num_chan; ++ ++ memset(buf_sizes, 0, 32 * sizeof(WORD32)); ++ ++ err_code = ++ ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_EXT_ELE_BUF_SIZES, &buf_sizes[0][0]); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_EXT_ELE_BUF_SIZES"); ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_EXT_ELE_PTR, &p_array); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_EXT_ELE_PTR"); ++ ++ err_code = ++ ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_SET_BUFF_PTR, 0); ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_SET_BUFF_PTR"); ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_NUM_ELE, &num_elements); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_NUM_ELE"); ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_NUM_CONFIG_EXT, &num_config_ext); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_NUM_CONFIG_EXT"); ++ ++ for (ii = 0; ii < num_config_ext; ii++) { ++ /*copy loudness bitstream*/ ++ if (buf_sizes[0][ii] > 0) { ++ memcpy(mDrcInBuf, p_array[0][ii], buf_sizes[0][ii]); ++ ++ /*Set bitstream_split_format */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT, &bit_str_fmt); ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT"); ++ ++ /* Set number of bytes to be processed */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES_IL_BS, 0, ++ &buf_sizes[0][ii]); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES_IL_BS"); ++ ++ /* Execute process */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, ++ IA_CMD_TYPE_INIT_CPY_IL_BSF_BUFF, NULL); ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_CPY_IL_BSF_BUFF"); ++ ++ mDRCFlag = 1; ++ } ++ } ++ ++ for (ii = 0; ii < num_elements; ii++) { ++ /*copy config bitstream*/ ++ if (buf_sizes[1][ii] > 0) { ++ memcpy(mDrcInBuf, p_array[1][ii], buf_sizes[1][ii]); ++ /* Set number of bytes to be processed */ ++ ++ /*Set bitstream_split_format */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT, &bit_str_fmt); ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT"); ++ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES_IC_BS, 0, ++ &buf_sizes[1][ii]); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES_IC_BS"); ++ ++ /* Execute process */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, ++ IA_CMD_TYPE_INIT_CPY_IC_BSF_BUFF, NULL); ++ ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_CPY_IC_BSF_BUFF"); ++ ++ mDRCFlag = 1; ++ } ++ } ++ ++ if (mDRCFlag == 1) { ++ mMpegDDRCPresent = 1; ++ } else { ++ mMpegDDRCPresent = 0; ++ } ++ ++ /*Read interface buffer config file bitstream*/ ++ if (mMpegDDRCPresent == 1) { ++ WORD32 interface_is_present = 1; ++ WORD32 frame_length; ++ ++ if (i_sbr_mode != 0) { ++ if (i_sbr_mode == 1) { ++ frame_length = 2048; ++ } else if (i_sbr_mode == 3) { ++ frame_length = 4096; ++ } else { ++ frame_length = 1024; ++ } ++ } else { ++ frame_length = 4096; ++ } ++ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_DRC_DEC_CONFIG_PARAM_FRAME_SIZE, &frame_length); ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_FRAME_SIZE"); ++ ++ err_code = ++ ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_DRC_DEC_CONFIG_PARAM_INT_PRESENT, &interface_is_present); ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_INT_PRESENT"); ++ ++ /* Execute process */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, ++ IA_CMD_TYPE_INIT_CPY_IN_BSF_BUFF, NULL); ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_CPY_IN_BSF_BUFF"); ++ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, ++ IA_CMD_TYPE_INIT_PROCESS, NULL); ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_PROCESS"); ++ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_DRC_DEC_CONFIG_PARAM_NUM_CHANNELS, &uo_num_chan); ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_NUM_CHANNELS"); ++ } ++ } ++ } ++#endif ++ ++ return IA_NO_ERROR; ++} ++IA_ERRORCODE SoftXAAC::decodeXAACStream(uint8_t* inBuffer, uint32_t inBufferLength, ++ int32_t* bytesConsumed, int32_t* outBytes) { ++ if (mInputBufferSize < inBufferLength) { ++ ALOGE("Cannot config AAC, input buffer size %d < inBufferLength %d", mInputBufferSize, ++ inBufferLength); ++ return -1; ++ } ++ ++ /* Copy the buffer passed by Android plugin to codec input buffer */ ++ memcpy(mInputBuffer, inBuffer, inBufferLength); ++ ++ /* Set number of bytes to be processed */ ++ IA_ERRORCODE err_code = ++ ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_INPUT_BYTES, 0, &inBufferLength); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES"); ++ ++ /* Execute process */ ++ err_code = ++ ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DO_EXECUTE, NULL); ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DO_EXECUTE"); ++ ++ UWORD32 ui_exec_done; ++ WORD32 i_num_preroll = 0; ++ /* Checking for end of processing */ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DONE_QUERY, ++ &ui_exec_done); ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DONE_QUERY"); ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_GET_NUM_PRE_ROLL_FRAMES, ++ &i_num_preroll); ++ ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GET_NUM_PRE_ROLL_FRAMES"); ++ { ++ int32_t pi_preroll_frame_offset = 0; ++ do { ++#ifdef ENABLE_MPEG_D_DRC ++ if (ui_exec_done != 1) { ++ VOID* p_array; // ITTIAM:buffer to handle gain payload ++ WORD32 buf_size = 0; // ITTIAM:gain payload length ++ WORD32 bit_str_fmt = 1; ++ WORD32 gain_stream_flag = 1; ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN, &buf_size); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN"); ++ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF, &p_array); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF"); ++ ++ if (buf_size > 0) { ++ /*Set bitstream_split_format */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT, &bit_str_fmt); ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT"); ++ ++ memcpy(mDrcInBuf, p_array, buf_size); ++ /* Set number of bytes to be processed */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES_BS, ++ 0, &buf_size); ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT"); ++ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_DRC_DEC_CONFIG_GAIN_STREAM_FLAG, ++ &gain_stream_flag); ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT"); ++ ++ /* Execute process */ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, ++ IA_CMD_TYPE_INIT_CPY_BSF_BUFF, NULL); ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT"); ++ ++ mMpegDDRCPresent = 1; ++ } ++ } ++#endif ++ /* How much buffer is used in input buffers */ ++ err_code = ++ ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CURIDX_INPUT_BUF, ++ 0, bytesConsumed); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_CURIDX_INPUT_BUF"); ++ ++ /* Get the output bytes */ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, ++ IA_API_CMD_GET_OUTPUT_BYTES, 0, outBytes); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_OUTPUT_BYTES"); ++#ifdef ENABLE_MPEG_D_DRC ++ ++ if (mMpegDDRCPresent == 1) { ++ memcpy(mDrcInBuf, mOutputBuffer + pi_preroll_frame_offset, *outBytes); ++ pi_preroll_frame_offset += *outBytes; ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES, ++ 0, outBytes); ++ RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES"); ++ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_EXECUTE, ++ IA_CMD_TYPE_DO_EXECUTE, NULL); ++ RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DO_EXECUTE"); ++ ++ memcpy(mOutputBuffer, mDrcOutBuf, *outBytes); ++ } ++#endif ++ i_num_preroll--; ++ } while (i_num_preroll > 0); ++ } ++ return IA_NO_ERROR; ++} ++ ++IA_ERRORCODE SoftXAAC::deInitXAACDecoder() { ++ ALOGI("deInitXAACDecoder"); ++ ++ /* Tell that the input is over in this buffer */ ++ IA_ERRORCODE err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INPUT_OVER, 0, NULL); ++ ++ /* Irrespective of error returned in IA_API_CMD_INPUT_OVER, free allocated memory */ ++ for (void* buf : mMemoryVec) { ++ free(buf); ++ } ++ mMemoryVec.clear(); ++ return err_code; ++} ++ ++IA_ERRORCODE SoftXAAC::deInitMPEGDDDrc() { ++ ALOGI("deInitMPEGDDDrc"); ++ ++ for (void* buf : mDrcMemoryVec) { ++ free(buf); ++ } ++ mDrcMemoryVec.clear(); ++ return IA_NO_ERROR; ++} ++ ++IA_ERRORCODE SoftXAAC::getXAACStreamInfo() { ++ IA_ERRORCODE err_code = IA_NO_ERROR; ++ ++ /* Sampling frequency */ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_SAMP_FREQ, &mSampFreq); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_SAMP_FREQ"); ++ ++ /* Total Number of Channels */ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_NUM_CHANNELS, &mNumChannels); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_NUM_CHANNELS"); ++ if (mNumChannels > MAX_CHANNEL_COUNT) { ++ ALOGE(" No of channels are more than max channels\n"); ++ return IA_FATAL_ERROR; ++ } ++ ++ /* PCM word size */ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_PCM_WDSZ, &mPcmWdSz); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_PCM_WDSZ"); ++ if ((mPcmWdSz / 8) != 2) { ++ ALOGE("Invalid Number of bytes per sample: %d, Expected is 2", mPcmWdSz); ++ return IA_FATAL_ERROR; ++ } ++ ++ /* channel mask to tell the arrangement of channels in bit stream */ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_CHANNEL_MASK, &mChannelMask); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_CHANNEL_MASK"); ++ ++ /* Channel mode to tell MONO/STEREO/DUAL-MONO/NONE_OF_THESE */ ++ UWORD32 ui_channel_mode; ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_CHANNEL_MODE, &ui_channel_mode); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_CHANNEL_MODE"); ++ if (ui_channel_mode == 0) ++ ALOGV("Channel Mode: MONO_OR_PS\n"); ++ else if (ui_channel_mode == 1) ++ ALOGV("Channel Mode: STEREO\n"); ++ else if (ui_channel_mode == 2) ++ ALOGV("Channel Mode: DUAL-MONO\n"); ++ else ++ ALOGV("Channel Mode: NONE_OF_THESE or MULTICHANNEL\n"); ++ ++ /* Channel mode to tell SBR PRESENT/NOT_PRESENT */ ++ UWORD32 ui_sbr_mode; ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_SBR_MODE, &ui_sbr_mode); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_SBR_MODE"); ++ if (ui_sbr_mode == 0) ++ ALOGV("SBR Mode: NOT_PRESENT\n"); ++ else if (ui_sbr_mode == 1) ++ ALOGV("SBR Mode: PRESENT\n"); ++ else ++ ALOGV("SBR Mode: ILLEGAL\n"); ++ ++ /* mOutputFrameLength = 1024 * (1 + SBR_MODE) for AAC */ ++ /* For USAC it could be 1024 * 3 , support to query */ ++ /* not yet added in codec */ ++ mOutputFrameLength = 1024 * (1 + ui_sbr_mode); ++ ++ ALOGI("mOutputFrameLength %d ui_sbr_mode %d", mOutputFrameLength, ui_sbr_mode); ++ ++ return IA_NO_ERROR; ++} ++ ++IA_ERRORCODE SoftXAAC::setXAACDRCInfo(int32_t drcCut, int32_t drcBoost, int32_t drcRefLevel, ++ int32_t drcHeavyCompression ++#ifdef ENABLE_MPEG_D_DRC ++ , ++ int32_t drEffectType ++#endif ++) { ++ IA_ERRORCODE err_code = IA_NO_ERROR; ++ ++ int32_t ui_drc_enable = 1; ++ int32_t i_effect_type, i_target_loudness, i_loud_norm; ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_ENABLE, &ui_drc_enable); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_ENABLE"); ++ if (drcCut != -1) { ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_CUT, &drcCut); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_CUT"); ++ } ++ ++ if (drcBoost != -1) { ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_BOOST, &drcBoost); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_BOOST"); ++ } ++ ++ if (drcRefLevel != -1) { ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LEVEL, &drcRefLevel); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LEVEL"); ++ } ++#ifdef ENABLE_MPEG_D_DRC ++ if (drcRefLevel != -1) { ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_DRC_TARGET_LOUDNESS, &drcRefLevel); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_DRC_TARGET_LOUDNESS"); ++ } ++#endif ++ if (drcHeavyCompression != -1) { ++ err_code = ++ ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_HEAVY_COMP, &drcHeavyCompression); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_HEAVY_COMP"); ++ } ++ ++#ifdef ENABLE_MPEG_D_DRC ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_DRC_EFFECT_TYPE, &drEffectType); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_DRC_EFFECT_TYPE"); ++#endif ++ ++#ifdef ENABLE_MPEG_D_DRC ++ /*Set Effect Type*/ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_EFFECT_TYPE, &i_effect_type); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_EFFECT_TYPE"); ++ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_DRC_DEC_CONFIG_DRC_EFFECT_TYPE, &i_effect_type); ++ ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_DRC_EFFECT_TYPE"); ++ ++ /*Set target loudness */ ++ err_code = ++ ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LOUDNESS, &i_target_loudness); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LOUDNESS"); ++ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_DRC_DEC_CONFIG_DRC_TARGET_LOUDNESS, &i_target_loudness); ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_DRC_TARGET_LOUDNESS"); ++ ++ /*Set loud_norm_flag*/ ++ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, ++ IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_LOUD_NORM, &i_loud_norm); ++ RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_LOUD_NORM"); ++ ++ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, ++ IA_DRC_DEC_CONFIG_DRC_LOUD_NORM, &i_loud_norm); ++ ++ RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_DRC_LOUD_NORM"); ++ ++#endif ++ ++ return IA_NO_ERROR; ++} ++ ++} // namespace android ++ ++__attribute__((cfi_canonical_jump_table)) ++android::SoftOMXComponent* createSoftOMXComponent(const char* name, ++ const OMX_CALLBACKTYPE* callbacks, ++ OMX_PTR appData, OMX_COMPONENTTYPE** component) { ++ ALOGI("createSoftOMXComponent for SoftXAACDEC"); ++ return new android::SoftXAAC(name, callbacks, appData, component); ++} +diff --git a/media/libstagefright/codecs/xaacdec/SoftXAAC.h b/media/libstagefright/codecs/xaacdec/SoftXAAC.h +new file mode 100644 +index 0000000..a62a797 +--- /dev/null ++++ b/media/libstagefright/codecs/xaacdec/SoftXAAC.h +@@ -0,0 +1,130 @@ ++/* ++ * Copyright (C) 2018 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 SOFTXAAC_H_ ++#define SOFTXAAC_H_ ++ ++#include ++ ++#include ++#include ++#include ++ ++#include "ixheaacd_type_def.h" ++#include "ixheaacd_error_standards.h" ++#include "ixheaacd_error_handler.h" ++#include "ixheaacd_apicmd_standards.h" ++#include "ixheaacd_memory_standards.h" ++#include "ixheaacd_aac_config.h" ++ ++#include "impd_apicmd_standards.h" ++#include "impd_drc_config_params.h" ++ ++extern "C" IA_ERRORCODE ixheaacd_dec_api(pVOID p_ia_module_obj, WORD32 i_cmd, WORD32 i_idx, ++ pVOID pv_value); ++extern "C" IA_ERRORCODE ia_drc_dec_api(pVOID p_ia_module_obj, WORD32 i_cmd, WORD32 i_idx, ++ pVOID pv_value); ++extern "C" IA_ERRORCODE ixheaacd_get_config_param(pVOID p_ia_process_api_obj, pWORD32 pi_samp_freq, ++ pWORD32 pi_num_chan, pWORD32 pi_pcm_wd_sz, ++ pWORD32 pi_channel_mask); ++ ++namespace android { ++ ++struct SoftXAAC : public SimpleSoftOMXComponent { ++ SoftXAAC(const char* name, const OMX_CALLBACKTYPE* callbacks, OMX_PTR appData, ++ OMX_COMPONENTTYPE** component); ++ ++ protected: ++ virtual ~SoftXAAC(); ++ ++ virtual OMX_ERRORTYPE internalGetParameter(OMX_INDEXTYPE index, OMX_PTR params); ++ ++ virtual OMX_ERRORTYPE internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params); ++ ++ virtual void onQueueFilled(OMX_U32 portIndex); ++ virtual void onPortFlushCompleted(OMX_U32 portIndex); ++ virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled); ++ virtual void onReset(); ++ ++ private: ++ enum { ++ kNumInputBuffers = 4, ++ kNumOutputBuffers = 4, ++ kNumDelayBlocksMax = 8, ++ }; ++ ++ bool mIsADTS; ++ size_t mInputBufferCount; ++ size_t mOutputBufferCount; ++ bool mSignalledError; ++ OMX_BUFFERHEADERTYPE* mLastInHeader; ++ int64_t mPrevTimestamp; ++ int64_t mCurrentTimestamp; ++ uint32_t mBufSize; ++ ++ enum { NONE, AWAITING_DISABLED, AWAITING_ENABLED } mOutputPortSettingsChange; ++ ++ void initPorts(); ++ IA_ERRORCODE initDecoder(); ++ bool isConfigured() const; ++ IA_ERRORCODE drainDecoder(); ++ IA_ERRORCODE initXAACDecoder(); ++ IA_ERRORCODE deInitXAACDecoder(); ++ IA_ERRORCODE initMPEGDDDrc(); ++ IA_ERRORCODE deInitMPEGDDDrc(); ++ IA_ERRORCODE configXAACDecoder(uint8_t* inBuffer, uint32_t inBufferLength); ++ IA_ERRORCODE configMPEGDDrc(); ++ IA_ERRORCODE decodeXAACStream(uint8_t* inBuffer, uint32_t inBufferLength, ++ int32_t* bytesConsumed, int32_t* outBytes); ++ ++ IA_ERRORCODE configflushDecode(); ++ IA_ERRORCODE getXAACStreamInfo(); ++ IA_ERRORCODE setXAACDRCInfo(int32_t drcCut, int32_t drcBoost, int32_t drcRefLevel, ++ int32_t drcHeavyCompression ++#ifdef ENABLE_MPEG_D_DRC ++ , ++ int32_t drEffectType ++#endif ++ ); ++ ++ bool mEndOfInput; ++ bool mEndOfOutput; ++ ++ void* mXheaacCodecHandle; ++ void* mMpegDDrcHandle; ++ uint32_t mInputBufferSize; ++ uint32_t mOutputFrameLength; ++ int8_t* mInputBuffer; ++ int8_t* mOutputBuffer; ++ int32_t mSampFreq; ++ int32_t mNumChannels; ++ int32_t mPcmWdSz; ++ int32_t mChannelMask; ++ bool mIsCodecInitialized; ++ bool mIsCodecConfigFlushRequired; ++ int8_t* mDrcInBuf; ++ int8_t* mDrcOutBuf; ++ int32_t mMpegDDRCPresent; ++ int32_t mDRCFlag; ++ Vector mMemoryVec; ++ Vector mDrcMemoryVec; ++ ++ DISALLOW_EVIL_CONSTRUCTORS(SoftXAAC); ++}; ++ ++} // namespace android ++ ++#endif // SOFTXAAC_H_ +diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp +index 6ba7896..a15148a 100644 +--- a/media/libstagefright/omx/Android.bp ++++ b/media/libstagefright/omx/Android.bp +@@ -179,6 +179,38 @@ cc_library_shared { + }, + } + ++cc_defaults { ++ name: "libstagefright_softomx-defaults", ++ // TODO (b/316432618) Software OMX codecs are no longer used, disable building them till ++ // this code is removed completely. ++ vendor_available: true, ++ ++ cflags: [ ++ "-Werror", ++ ], ++ ++ header_libs: [ ++ "media_plugin_headers" ++ ], ++ ++ shared_libs: [ ++ "libstagefright_softomx", ++ "libstagefright_foundation", ++ "libutils", ++ "liblog", ++ ], ++ ++ sanitize: { ++ misc_undefined: [ ++ "signed-integer-overflow", ++ "unsigned-integer-overflow", ++ ], ++ cfi: true, ++ }, ++ ++ compile_multilib: "32", ++} ++ + cc_library_shared { + name: "libstagefright_omx_utils", + vendor_available: true, +diff --git a/media/libstagefright/omx/OMXStore.cpp b/media/libstagefright/omx/OMXStore.cpp +index b2d5a70..3be56c8 100644 +--- a/media/libstagefright/omx/OMXStore.cpp ++++ b/media/libstagefright/omx/OMXStore.cpp +@@ -161,7 +161,6 @@ void OMXStore::addPlugin(OMXPluginBase *plugin) { + } + } + if (skip) { +- continue; + } + } + +diff --git a/services/mediacodec/Android.bp b/services/mediacodec/Android.bp +index 506b3bc..a2f17c2 100644 +--- a/services/mediacodec/Android.bp ++++ b/services/mediacodec/Android.bp +@@ -95,6 +95,31 @@ cc_binary { + "android.hidl.memory@1.0", + ], + ++ runtime_libs: [ ++ "libstagefright_soft_aacdec", ++ "libstagefright_soft_aacenc", ++ "libstagefright_soft_amrdec", ++ "libstagefright_soft_amrnbenc", ++ "libstagefright_soft_amrwbenc", ++ "libstagefright_soft_avcdec", ++ "libstagefright_soft_avcenc", ++ "libstagefright_soft_flacdec", ++ "libstagefright_soft_flacenc", ++ "libstagefright_soft_g711dec", ++ "libstagefright_soft_gsmdec", ++ "libstagefright_soft_hevcdec", ++ "libstagefright_soft_mp3dec", ++ "libstagefright_soft_mpeg2dec", ++ "libstagefright_soft_mpeg4dec", ++ "libstagefright_soft_mpeg4enc", ++ "libstagefright_soft_opusdec", ++ "libstagefright_soft_rawdec", ++ "libstagefright_soft_vorbisdec", ++ "libstagefright_soft_vpxdec", ++ "libstagefright_soft_vpxenc", ++ "libstagefright_softomx_plugin", ++ ], ++ + // OMX interfaces force this to stay in 32-bit mode; + compile_multilib: "32", + +-- +2.49.0 + diff --git a/android-16.0.0_r2/frameworks/base/0001-ignore-cgroup-error.patch b/android-16.0.0_r2/frameworks/base/0001-ignore-cgroup-error.patch new file mode 100644 index 0000000..ef489af --- /dev/null +++ b/android-16.0.0_r2/frameworks/base/0001-ignore-cgroup-error.patch @@ -0,0 +1,25 @@ +From 3a364f05e246121b795300d56b42e6e0ae8c10b4 Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Sat, 11 Nov 2023 10:30:11 +0800 +Subject: [PATCH] ignore cgroup error + +--- + services/core/java/com/android/server/am/ProcessList.java | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java +index ad47e67b9..e464f74dc 100644 +--- a/services/core/java/com/android/server/am/ProcessList.java ++++ b/services/core/java/com/android/server/am/ProcessList.java +@@ -2594,7 +2594,7 @@ public final class ProcessList { + "Unable to create process group for " + + app.processName + " (" + startResult.pid + ")"); + } else { +- throw new AssertionError("Unable to create process group for " ++ Slog.e(ActivityManagerService.TAG, "Unable to create process group for " + + app.processName + " (" + startResult.pid + ")"); + } + } else { +-- +2.49.0 + diff --git a/android-16.0.0_r2/frameworks/native/0001-fix-booting.patch b/android-16.0.0_r2/frameworks/native/0001-fix-booting.patch new file mode 100644 index 0000000..733617d --- /dev/null +++ b/android-16.0.0_r2/frameworks/native/0001-fix-booting.patch @@ -0,0 +1,59 @@ +From 37e20b445a0a05fa8e01678d1266d10214ed8af4 Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Sun, 9 May 2021 23:04:00 +0800 +Subject: [PATCH] fix booting + +--- + libs/binder/Binder.cpp | 1 + + libs/binder/IPCThreadState.cpp | 2 +- + libs/binder/ProcessState.cpp | 3 +++ + 3 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp +index 9883eb2..6b0e1c8 100644 +--- a/libs/binder/Binder.cpp ++++ b/libs/binder/Binder.cpp +@@ -524,6 +524,7 @@ void BBinder::setRequestingSid(bool requestingSid) + "setRequestingSid() should not be called after a binder object " + "is parceled/sent to another process"); + ++ requestingSid = false; // HACKED + Extras* e = mExtras.load(std::memory_order_acquire); + + if (!e) { +diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp +index 1c1b6f3..bc1aec0 100644 +--- a/libs/binder/IPCThreadState.cpp ++++ b/libs/binder/IPCThreadState.cpp +@@ -1460,7 +1460,7 @@ status_t IPCThreadState::executeCommand(int32_t cmd) + clearPropagateWorkSource(); + + mCallingPid = tr.sender_pid; +- mCallingSid = reinterpret_cast(tr_secctx.secctx); ++ mCallingSid = "HACKED"; + mCallingUid = tr.sender_euid; + mHasExplicitIdentity = false; + mLastTransactionBinderFlags = tr.flags; +diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp +index 0bec379..7a9c411 100644 +--- a/libs/binder/ProcessState.cpp ++++ b/libs/binder/ProcessState.cpp +@@ -229,12 +229,15 @@ bool ProcessState::becomeContextManager() + { + std::unique_lock _l(mLock); + ++#if 0 + flat_binder_object obj { + .flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX, + }; + + int result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR_EXT, &obj); ++#endif + ++ int result = 1; + // fallback to original method + if (result != 0) { + android_errorWriteLog(0x534e4554, "121035042"); +-- +2.49.0 + diff --git a/android-16.0.0_r2/packages/modules/Connectivity/0001-fix-booting.patch b/android-16.0.0_r2/packages/modules/Connectivity/0001-fix-booting.patch new file mode 100644 index 0000000..bd31157 --- /dev/null +++ b/android-16.0.0_r2/packages/modules/Connectivity/0001-fix-booting.patch @@ -0,0 +1,58 @@ +From 2650f80257f4c2eb73ab1b81e7c0eea23bb1c02a Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Thu, 5 Oct 2023 22:18:09 +0800 +Subject: [PATCH 1/2] fix booting + +--- + bpf/loader/NetBpfLoad.cpp | 8 ++++++-- + .../com_android_server_connectivity_ClatCoordinator.cpp | 1 + + 2 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/bpf/loader/NetBpfLoad.cpp b/bpf/loader/NetBpfLoad.cpp +index bdc2e8c..1527b99 100644 +--- a/bpf/loader/NetBpfLoad.cpp ++++ b/bpf/loader/NetBpfLoad.cpp +@@ -1865,12 +1865,14 @@ static int doLoad(char** argv, char * const envp[]) { + // kernel does not have CONFIG_BPF_JIT=y) + // BPF_JIT is required by R VINTF (which means 4.14/4.19/5.4 kernels), + // but 4.14/4.19 were released with P & Q, and only 5.4 is new in R+. +- if (writeProcSysFile("/proc/sys/net/core/bpf_jit_enable", "1\n")) return 1; ++ if (writeProcSysFile("/proc/sys/net/core/bpf_jit_enable", "1\n")) ++ ALOGE("write 1 to /proc/sys/net/core/bpf_jit_enable FAILED"); + + // Enable JIT kallsyms export for privileged users only + // (Note: this (open) will fail with ENOENT 'No such file or directory' if + // kernel does not have CONFIG_HAVE_EBPF_JIT=y) +- if (writeProcSysFile("/proc/sys/net/core/bpf_jit_kallsyms", "1\n")) return 1; ++ if (writeProcSysFile("/proc/sys/net/core/bpf_jit_kallsyms", "1\n")) ++ ALOGE("write 1 to /proc/sys/net/core/bpf_jit_kallsyms FAILED"); + } + + // Create all the pin subdirectories +@@ -1899,9 +1901,11 @@ static int doLoad(char** argv, char * const envp[]) { + ALOGE("If this triggers reliably, you're probably missing kernel options or patches."); + ALOGE("If this triggers randomly, you might be hitting some memory allocation " + "problems or startup script race."); ++ #if 0 // HACKED + ALOGE("--- DO NOT EXPECT SYSTEM TO BOOT SUCCESSFULLY ---"); + sleep(20); + return 2; ++ #endif + } + } + +diff --git a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp +index 622fba8..fcb7fa0 100644 +--- a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp ++++ b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp +@@ -132,6 +132,7 @@ static void verifyClatPerms() { + + #undef V2 + ++ fatal = false; + if (fatal) abort(); + } + +-- +2.49.0 + diff --git a/android-16.0.0_r2/packages/modules/Connectivity/0002-ignore-nativeSynchronizeKernelRCU-error.patch b/android-16.0.0_r2/packages/modules/Connectivity/0002-ignore-nativeSynchronizeKernelRCU-error.patch new file mode 100644 index 0000000..a28b72d --- /dev/null +++ b/android-16.0.0_r2/packages/modules/Connectivity/0002-ignore-nativeSynchronizeKernelRCU-error.patch @@ -0,0 +1,24 @@ +From ba7f80bea4177bc442cd9ccf0e9456de1cda32f1 Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Thu, 5 Sep 2024 19:11:19 +0800 +Subject: [PATCH 2/2] ignore nativeSynchronizeKernelRCU error + +--- + .../native/bpfmapjni/com_android_net_module_util_BpfMap.cpp | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp +index d862f6b..8f5ecdf 100644 +--- a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp ++++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp +@@ -140,7 +140,6 @@ static void com_android_net_module_util_BpfMap_nativeSynchronizeKernelRCU(JNIEnv + const int pfSocket = socket(AF_KEY, SOCK_RAW | SOCK_CLOEXEC, PF_KEY_V2); + + if (pfSocket < 0) { +- jniThrowErrnoException(env, "nativeSynchronizeKernelRCU:socket", errno); + return; + } + +-- +2.49.0 + diff --git a/android-16.0.0_r2/system/bpf/0001-fix-booting.patch b/android-16.0.0_r2/system/bpf/0001-fix-booting.patch new file mode 100644 index 0000000..a066cae --- /dev/null +++ b/android-16.0.0_r2/system/bpf/0001-fix-booting.patch @@ -0,0 +1,29 @@ +From 55e045ad4fe9121a13dd12799a5ad77e0b43ec42 Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Sun, 15 Jun 2025 19:29:19 +0800 +Subject: [PATCH] fix booting + +Change-Id: I01e3abbbd3e879f9880177f1bb43ab634df0aec8 +--- + loader/Loader.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/loader/Loader.cpp b/loader/Loader.cpp +index 940ce19..336bb6a 100644 +--- a/loader/Loader.cpp ++++ b/loader/Loader.cpp +@@ -990,9 +990,11 @@ void legacyBpfLoader() { + ALOGE("If this triggers reliably, you're probably missing kernel options or patches."); + ALOGE("If this triggers randomly, you might be hitting some memory allocation " + "problems or startup script race."); ++ #if 0 + ALOGE("--- DO NOT EXPECT SYSTEM TO BOOT SUCCESSFULLY ---"); + sleep(20); + exit(121); ++ #endif + } + } + } +-- +2.49.0 + diff --git a/android-16.0.0_r2/system/core/0001-fix-booting.patch b/android-16.0.0_r2/system/core/0001-fix-booting.patch new file mode 100644 index 0000000..345ff75 --- /dev/null +++ b/android-16.0.0_r2/system/core/0001-fix-booting.patch @@ -0,0 +1,147 @@ +From a74c433d22faa74ec7d16fd7b7f5cdbcbc4aaef8 Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Sun, 9 May 2021 23:09:00 +0800 +Subject: [PATCH 1/7] fix booting + +--- + fs_mgr/libfstab/boot_config.cpp | 6 ++++-- + init/first_stage_init.cpp | 18 +++++++++++++++--- + init/init.cpp | 0 + init/property_service.cpp | 0 + init/service.cpp | 1 + + libcutils/ashmem-dev.cpp | 2 +- + rootdir/init.rc | 2 +- + 7 files changed, 22 insertions(+), 7 deletions(-) + mode change 100644 => 100755 init/init.cpp + mode change 100644 => 100755 init/property_service.cpp + +diff --git a/fs_mgr/libfstab/boot_config.cpp b/fs_mgr/libfstab/boot_config.cpp +index b21495e..7993d15 100644 +--- a/fs_mgr/libfstab/boot_config.cpp ++++ b/fs_mgr/libfstab/boot_config.cpp +@@ -154,13 +154,15 @@ bool GetKernelCmdlineFromString(const std::string& cmdline, const std::string& k + + void ImportKernelCmdline(const std::function& fn) { + std::string cmdline; +- android::base::ReadFileToString("/proc/cmdline", &cmdline); ++ android::base::ReadFileToString("/proc/self/cmdline", &cmdline); // HACKED ++ std::replace(cmdline.begin(), cmdline.end(), '\0', ' '); // HACKED + ImportKernelCmdlineFromString(android::base::Trim(cmdline), fn); + } + + bool GetKernelCmdline(const std::string& key, std::string* out) { + std::string cmdline; +- android::base::ReadFileToString("/proc/cmdline", &cmdline); ++ android::base::ReadFileToString("/proc/self/cmdline", &cmdline); // HACKED ++ std::replace(cmdline.begin(), cmdline.end(), '\0', ' '); // HACKED + return GetKernelCmdlineFromString(android::base::Trim(cmdline), key, out); + } + +diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp +index e06a645..6406662 100644 +--- a/init/first_stage_init.cpp ++++ b/init/first_stage_init.cpp +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -352,6 +353,8 @@ int FirstStageMain(int argc, char** argv) { + CHECKCALL(mkdir("/dev/pts", 0755)); + CHECKCALL(mkdir("/dev/socket", 0755)); + CHECKCALL(mkdir("/dev/dm-user", 0755)); ++ mount("/system/etc", "/etc", "none", MS_BIND, NULL); // cgroup fix ++ unshare(CLONE_NEWCGROUP); + CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL)); + #define MAKE_STR(x) __STRING(x) + CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC))); +@@ -420,7 +423,6 @@ int FirstStageMain(int argc, char** argv) { + for (const auto& [error_string, error_errno] : errors) { + LOG(ERROR) << error_string << " " << strerror(error_errno); + } +- LOG(FATAL) << "Init encountered errors starting first stage, aborting"; + } + + LOG(INFO) << "init first stage started!"; +@@ -557,12 +559,22 @@ int FirstStageMain(int argc, char** argv) { + 1); + + const char* path = "/system/bin/init"; +- const char* args[] = {path, "selinux_setup", nullptr}; ++ std::vector args = {path, "second_stage"}; ++ std::string init_cmdline; ++ android::base::ReadFileToString("/proc/self/cmdline", &init_cmdline); ++ std::replace(init_cmdline.begin(), init_cmdline.end(), '\0', ' '); ++ auto cmd_vector = android::base::Split(android::base::Trim(init_cmdline), " "); ++ int i = 0; ++ for (const auto& entry : cmd_vector) { ++ if (i++ == 0) continue; // ignore first arg '/init' ++ args.push_back(entry.c_str()); ++ } ++ args.push_back(nullptr); + auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + close(fd); +- execv(path, const_cast(args)); ++ execv(path, const_cast(args.data())); + + // execv() only returns if an error happened, in which case we + // panic and never fall through this conditional. +diff --git a/init/init.cpp b/init/init.cpp +old mode 100644 +new mode 100755 +diff --git a/init/property_service.cpp b/init/property_service.cpp +old mode 100644 +new mode 100755 +diff --git a/init/service.cpp b/init/service.cpp +index 5630020..bd1f43f 100644 +--- a/init/service.cpp ++++ b/init/service.cpp +@@ -77,6 +77,7 @@ namespace android { + namespace init { + + static Result ComputeContextFromExecutable(const std::string& service_path) { ++ se_hack1("HACKED"); + std::string computed_context; + + char* raw_con = nullptr; +diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp +index 80c4f4c..f4d9e2a 100644 +--- a/libcutils/ashmem-dev.cpp ++++ b/libcutils/ashmem-dev.cpp +@@ -176,7 +176,7 @@ static int __ashmem_open_locked() { + return -1; + } + +- android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(ashmem_device_path.c_str(), O_RDWR | O_CLOEXEC))); ++ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/ashmem", O_RDWR | O_CLOEXEC))); + if (!fd.ok()) { + ALOGE("Unable to open ashmem device: %m"); + return -1; +diff --git a/rootdir/init.rc b/rootdir/init.rc +index 471059b..52c967d 100644 +--- a/rootdir/init.rc ++++ b/rootdir/init.rc +@@ -15,6 +15,7 @@ import /system/etc/init/hw/init.${ro.zygote}.rc + on early-init + # Disable sysrq from keyboard + write /proc/sys/kernel/sysrq 0 ++ mount sysfs sysfs /sys remount rw nodev + + # Android doesn't need kernel module autoloading, and it causes SELinux + # denials. So disable it by setting modprobe to the empty string. Note: to +@@ -541,7 +542,6 @@ on post-fs + + # Once everything is setup, no need to modify /. + # The bind+remount combination allows this to work in containers. +- mount rootfs rootfs / remount bind ro nodev + + # Mount default storage into root namespace + mount none /mnt/user/0 /storage bind rec +-- +2.49.0 + diff --git a/android-16.0.0_r2/system/core/0002-allow-override-ro.-prop.patch b/android-16.0.0_r2/system/core/0002-allow-override-ro.-prop.patch new file mode 100644 index 0000000..0992f12 --- /dev/null +++ b/android-16.0.0_r2/system/core/0002-allow-override-ro.-prop.patch @@ -0,0 +1,25 @@ +From 810a90e48678b11038ad7982dd9bb1e04c1e1efb Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Sat, 26 Jun 2021 05:42:24 +0000 +Subject: [PATCH 2/7] allow override ro.* prop + +--- + init/property_service.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/init/property_service.cpp b/init/property_service.cpp +index 83e9a0d..bd55dcc 100755 +--- a/init/property_service.cpp ++++ b/init/property_service.cpp +@@ -1391,6 +1391,8 @@ static void ProcessKernelCmdline() { + android::fs_mgr::ImportKernelCmdline([&](const std::string& key, const std::string& value) { + if (StartsWith(key, ANDROIDBOOT_PREFIX)) { + InitPropertySet("ro.boot." + key.substr(ANDROIDBOOT_PREFIX.size()), value); ++ } else if (StartsWith(key, "ro.")) { ++ InitPropertySet(key, value); + } + }); + } +-- +2.49.0 + diff --git a/android-16.0.0_r2/system/core/0003-fix-first-stage-mount.patch b/android-16.0.0_r2/system/core/0003-fix-first-stage-mount.patch new file mode 100644 index 0000000..7475fa1 --- /dev/null +++ b/android-16.0.0_r2/system/core/0003-fix-first-stage-mount.patch @@ -0,0 +1,35 @@ +From 01ea704105418bbf7bc45d1199bef3d36db0c58d Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Sun, 27 Jun 2021 09:49:22 +0000 +Subject: [PATCH 3/7] ? fix first stage mount + +--- + init/first_stage_init.cpp | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp +index 6406662..13c7553 100644 +--- a/init/first_stage_init.cpp ++++ b/init/first_stage_init.cpp +@@ -530,6 +530,7 @@ int FirstStageMain(int argc, char** argv) { + if (!fsm) { + fsm = CreateFirstStageMount(cmdline); + } ++ #if 0 + if (!fsm) { + LOG(FATAL) << "FirstStageMount not available"; + } +@@ -539,8 +540,9 @@ int FirstStageMain(int argc, char** argv) { + } + + if (!fsm->DoFirstStageMount()) { +- LOG(FATAL) << "Failed to mount required partitions early ..."; ++ LOG(ERROR) << "Failed to mount required partitions early ..."; + } ++ #endif + } + + struct stat new_root_info {}; +-- +2.49.0 + diff --git a/android-16.0.0_r2/system/core/0004-ignore-input-subsystem.patch b/android-16.0.0_r2/system/core/0004-ignore-input-subsystem.patch new file mode 100644 index 0000000..a69042c --- /dev/null +++ b/android-16.0.0_r2/system/core/0004-ignore-input-subsystem.patch @@ -0,0 +1,26 @@ +From b3426e7aa82ad2ae5b0935fc53216335310310df Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Fri, 25 Jun 2021 15:56:47 +0000 +Subject: [PATCH 4/7] ignore input subsystem + +--- + rootdir/ueventd.rc | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc +index 3927501..404da8f 100644 +--- a/rootdir/ueventd.rc ++++ b/rootdir/ueventd.rc +@@ -12,9 +12,6 @@ subsystem drm + devname uevent_devpath + dirname /dev/dri + +-subsystem input +- devname uevent_devpath +- dirname /dev/input + + subsystem sound + devname uevent_devpath +-- +2.49.0 + diff --git a/android-16.0.0_r2/system/core/0005-ignore-devfs-mount.patch b/android-16.0.0_r2/system/core/0005-ignore-devfs-mount.patch new file mode 100644 index 0000000..558e747 --- /dev/null +++ b/android-16.0.0_r2/system/core/0005-ignore-devfs-mount.patch @@ -0,0 +1,24 @@ +From ddb69215b3cd4ecee0993fa6bbd1752b71ac511b Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Fri, 17 Dec 2021 22:44:33 +0800 +Subject: [PATCH 5/7] ignore devfs mount + +--- + init/first_stage_init.cpp | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp +index 13c7553..8485b3d 100644 +--- a/init/first_stage_init.cpp ++++ b/init/first_stage_init.cpp +@@ -349,7 +349,6 @@ int FirstStageMain(int argc, char** argv) { + CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1)); + // Get the basic filesystem setup we need put together in the initramdisk + // on / and then we'll let the rc file figure out the rest. +- CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755")); + CHECKCALL(mkdir("/dev/pts", 0755)); + CHECKCALL(mkdir("/dev/socket", 0755)); + CHECKCALL(mkdir("/dev/dm-user", 0755)); +-- +2.49.0 + diff --git a/android-16.0.0_r2/system/core/0006-auto-alloc-binder-devices.patch b/android-16.0.0_r2/system/core/0006-auto-alloc-binder-devices.patch new file mode 100644 index 0000000..2d67c04 --- /dev/null +++ b/android-16.0.0_r2/system/core/0006-auto-alloc-binder-devices.patch @@ -0,0 +1,24 @@ +From 4f325fbbcd4ff9c5ddedb6d3d3a1f587cfc950bd Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Thu, 6 Jan 2022 20:47:28 +0800 +Subject: [PATCH 6/7] auto alloc binder devices + +--- + rootdir/init.rc | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/rootdir/init.rc b/rootdir/init.rc +index 52c967d..bc92e33 100644 +--- a/rootdir/init.rc ++++ b/rootdir/init.rc +@@ -219,6 +219,7 @@ on init + mkdir /dev/binderfs + mount binder binder /dev/binderfs stats=global + chmod 0755 /dev/binderfs ++ exec -- /vendor/bin/binder_alloc /dev/binderfs/binder-control binder hwbinder vndbinder + + # Mount fusectl + mount fusectl none /sys/fs/fuse/connections +-- +2.49.0 + diff --git a/android-16.0.0_r2/system/core/0007-skip-fusectl-mount.patch b/android-16.0.0_r2/system/core/0007-skip-fusectl-mount.patch new file mode 100644 index 0000000..040b1a7 --- /dev/null +++ b/android-16.0.0_r2/system/core/0007-skip-fusectl-mount.patch @@ -0,0 +1,24 @@ +From 46eb689748f2c3d0ee19e0e247046249490a10b6 Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Sat, 2 Sep 2023 17:10:16 +0800 +Subject: [PATCH 7/7] skip fusectl mount + +--- + rootdir/init.rc | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/rootdir/init.rc b/rootdir/init.rc +index bc92e33..63ff049 100644 +--- a/rootdir/init.rc ++++ b/rootdir/init.rc +@@ -222,7 +222,6 @@ on init + exec -- /vendor/bin/binder_alloc /dev/binderfs/binder-control binder hwbinder vndbinder + + # Mount fusectl +- mount fusectl none /sys/fs/fuse/connections + + symlink /dev/binderfs/binder /dev/binder + symlink /dev/binderfs/hwbinder /dev/hwbinder +-- +2.49.0 + diff --git a/android-16.0.0_r2/system/hwservicemanager/0001-fix-booting.patch b/android-16.0.0_r2/system/hwservicemanager/0001-fix-booting.patch new file mode 100644 index 0000000..7d54db9 --- /dev/null +++ b/android-16.0.0_r2/system/hwservicemanager/0001-fix-booting.patch @@ -0,0 +1,28 @@ +From 20133571482acb99467b95058e393e19121bde44 Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Tue, 24 Jun 2025 23:24:25 +0800 +Subject: [PATCH] fix booting + +Change-Id: I27f6ed25cb3b2364dbbc909ce795e13a9a6e194e +--- + ServiceManager.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/ServiceManager.cpp b/ServiceManager.cpp +index 73582d2..056edbe 100644 +--- a/ServiceManager.cpp ++++ b/ServiceManager.cpp +@@ -47,8 +47,10 @@ AccessControl::CallingContext getBinderCallingContext() { + android_errorWriteLog(0x534e4554, "121035042"); + } + ++ #if 0 // HACKED + CHECK_EQ(nullptr, self->getServingStackPointer()) + << "Pid " << pid << " missing service context."; ++ #endif + + return AccessControl::getCallingContext(pid); + } else { +-- +2.49.0 + diff --git a/android-16.0.0_r2/system/libhwbinder/0001-fix-booting.patch b/android-16.0.0_r2/system/libhwbinder/0001-fix-booting.patch new file mode 100644 index 0000000..8eb6309 --- /dev/null +++ b/android-16.0.0_r2/system/libhwbinder/0001-fix-booting.patch @@ -0,0 +1,45 @@ +From 8d1808ead2eb6ccb2f87cf985a6879e8c8cf3c80 Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Sun, 9 May 2021 23:44:12 +0800 +Subject: [PATCH] fix booting + +--- + Binder.cpp | 1 + + ProcessState.cpp | 3 +++ + 2 files changed, 4 insertions(+) + +diff --git a/Binder.cpp b/Binder.cpp +index 6d26414..b657a0b 100644 +--- a/Binder.cpp ++++ b/Binder.cpp +@@ -96,6 +96,7 @@ bool BHwBinder::isRequestingSid() { + } + + void BHwBinder::setRequestingSid(bool requestingSid) { ++ requestingSid = false; // HACKED + Extras* e = mExtras.load(std::memory_order_acquire); + + if (!e) { +diff --git a/ProcessState.cpp b/ProcessState.cpp +index 4b2f4fc..2c2c530 100644 +--- a/ProcessState.cpp ++++ b/ProcessState.cpp +@@ -128,12 +128,15 @@ void ProcessState::becomeContextManager() + { + AutoMutex _l(mLock); + ++#if 0 // HACKED (?) + flat_binder_object obj { + .flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX, + }; + + status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR_EXT, &obj); ++#endif + ++ status_t result = 1; + // fallback to original method + if (result != 0) { + android_errorWriteLog(0x534e4554, "121035042"); +-- +2.49.0 + diff --git a/android-16.0.0_r2/system/libvintf/0001-ignore-compatibility-check.patch b/android-16.0.0_r2/system/libvintf/0001-ignore-compatibility-check.patch new file mode 100644 index 0000000..5945b59 --- /dev/null +++ b/android-16.0.0_r2/system/libvintf/0001-ignore-compatibility-check.patch @@ -0,0 +1,24 @@ +From a9b5b360b730768adc58f0bd203c65d88915fe31 Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Sat, 15 Oct 2022 09:12:31 +0800 +Subject: [PATCH 1/2] ignore compatibility check + +--- + VintfObject.cpp | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/VintfObject.cpp b/VintfObject.cpp +index 708e58c..fb0b72e 100644 +--- a/VintfObject.cpp ++++ b/VintfObject.cpp +@@ -744,7 +744,6 @@ int32_t VintfObject::checkCompatibility(std::string* error, CheckFlags::Type fla + error->insert(0, + "Runtime info and framework compatibility matrix are incompatible: "); + } +- return INCOMPATIBLE; + } + } + +-- +2.49.0 + diff --git a/android-16.0.0_r2/system/libvintf/0002-ignore-proc-config.gz-failed-read.patch b/android-16.0.0_r2/system/libvintf/0002-ignore-proc-config.gz-failed-read.patch new file mode 100644 index 0000000..5212211 --- /dev/null +++ b/android-16.0.0_r2/system/libvintf/0002-ignore-proc-config.gz-failed-read.patch @@ -0,0 +1,24 @@ +From 2badf1f0d45dcd2619a6b05b396bb133f08cbc32 Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Thu, 5 Sep 2024 19:05:14 +0800 +Subject: [PATCH 2/2] ignore /proc/config.gz failed read + +--- + KernelConfigs.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/KernelConfigs.cpp b/KernelConfigs.cpp +index 3de65ea..3583d66 100644 +--- a/KernelConfigs.cpp ++++ b/KernelConfigs.cpp +@@ -34,6 +34,7 @@ status_t LoadKernelConfigs(std::map* configs) { + gzFile f = gzopen("/proc/config.gz", "rb"); + if (f == NULL) { + LOG(ERROR) << "Could not open /proc/config.gz: " << errno; ++ errno = 0; // HACKED + return -errno; + } + +-- +2.49.0 + diff --git a/android-16.0.0_r2/system/netd/0001-fix-booting.patch b/android-16.0.0_r2/system/netd/0001-fix-booting.patch new file mode 100644 index 0000000..86af785 --- /dev/null +++ b/android-16.0.0_r2/system/netd/0001-fix-booting.patch @@ -0,0 +1,89 @@ +From 0c2bc373eaea2c413570bc64471d2063c86209b4 Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Sat, 31 Jul 2021 06:14:33 +0000 +Subject: [PATCH] fix booting + +Change-Id: I87b1c6fca9361a66a021a3dc484f4d69224744a8 +--- + server/BandwidthController.cpp | 1 + + server/Controllers.cpp | 2 -- + server/IptablesRestoreController.cpp | 1 + + server/TetherController.cpp | 2 ++ + server/main.cpp | 1 - + 5 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/server/BandwidthController.cpp b/server/BandwidthController.cpp +index 8a96738..f1cbf14 100644 +--- a/server/BandwidthController.cpp ++++ b/server/BandwidthController.cpp +@@ -527,6 +527,7 @@ int BandwidthController::updateQuota(const std::string& quotaName, int64_t bytes + if (!isOk(file)) { + int res = errno; + ALOGE("Updating quota %s failed (%s)", quotaName.c_str(), toString(file).c_str()); ++ res = 0; // HACKED + return -res; + } + // TODO: should we propagate this error? +diff --git a/server/Controllers.cpp b/server/Controllers.cpp +index 48d0c50..50b8408 100644 +--- a/server/Controllers.cpp ++++ b/server/Controllers.cpp +@@ -326,7 +326,6 @@ void Controllers::init() { + // As such simply exit netd. This may crash loop the system, but by failing + // to bootup we will trigger rollback and thus this offers us protection against + // a mainline update breaking things. +- exit(1); + } + gLog.info("Enabling bandwidth control: %" PRId64 "us", s.getTimeAndResetUs()); + +@@ -339,7 +338,6 @@ void Controllers::init() { + netdutils::Status xStatus = XfrmController::Init(); + if (!isOk(xStatus)) { + gLog.error("Failed to initialize XfrmController (%s)", netdutils::toString(xStatus).c_str()); +- exit(3); + }; + gLog.info("Initializing XfrmController: %" PRId64 "us", s.getTimeAndResetUs()); + } +diff --git a/server/IptablesRestoreController.cpp b/server/IptablesRestoreController.cpp +index 49b48d3..07bdda4 100644 +--- a/server/IptablesRestoreController.cpp ++++ b/server/IptablesRestoreController.cpp +@@ -349,6 +349,7 @@ int IptablesRestoreController::execute(const IptablesTarget target, const std::s + if (target == V6 || target == V4V6) { + res |= sendCommand(IP6TABLES_PROCESS, command, output); + } ++ res = 0; // ignore iptables error + return res; + } + +diff --git a/server/TetherController.cpp b/server/TetherController.cpp +index b159d95..a582cd8 100644 +--- a/server/TetherController.cpp ++++ b/server/TetherController.cpp +@@ -913,9 +913,11 @@ StatusOr TetherController::getTetherStats() { + } + + if (int ret = addForwardChainStats(statsList, statsString, parsedIptablesOutput)) { ++#if 0 + return statusFromErrno(-ret, StringPrintf("failed to parse %s tether stats:\n%s", + target == V4 ? "IPv4": "IPv6", + parsedIptablesOutput.c_str())); ++#endif + } + } + +diff --git a/server/main.cpp b/server/main.cpp +index d27fd76..1a79b83 100644 +--- a/server/main.cpp ++++ b/server/main.cpp +@@ -142,7 +142,6 @@ int main() { + + if (libnetd_updatable_init(cg2_path.c_str())) { + ALOGE("libnetd_updatable_init failed"); +- exit(1); + } + gLog.info("libnetd_updatable_init success"); + +-- +2.49.0 + diff --git a/android-16.0.0_r2/system/vold/0001-ignore-project-quota-error.patch b/android-16.0.0_r2/system/vold/0001-ignore-project-quota-error.patch new file mode 100644 index 0000000..92ec3f2 --- /dev/null +++ b/android-16.0.0_r2/system/vold/0001-ignore-project-quota-error.patch @@ -0,0 +1,24 @@ +From c237d9bed4f26136f8687b539a8836a2ab07158c Mon Sep 17 00:00:00 2001 +From: Ziyang Zhou +Date: Sat, 6 Aug 2022 10:19:11 +0800 +Subject: [PATCH] ignore project quota error + +--- + Utils.cpp | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/Utils.cpp b/Utils.cpp +index 9ad828c..b4ebc7a 100644 +--- a/Utils.cpp ++++ b/Utils.cpp +@@ -246,7 +246,6 @@ int SetQuotaProjectId(const std::string& path, long projectId) { + ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx); + if (ret == -1) { + PLOG(ERROR) << "Failed to set project id on " << path; +- return ret; + } + return 0; + } +-- +2.49.0 +