22409 lines
809 KiB
Diff
22409 lines
809 KiB
Diff
From 26fd52895688f7e4d583ab25a1fe2b15451bdb3b Mon Sep 17 00:00:00 2001
|
|
From: Ziyang Zhou <ziyang.zhou@outlook.com>
|
|
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 <assert.h>
|
|
+
|
|
+#define LOG_TAG "SoftAAC2_DrcWrapper"
|
|
+//#define LOG_NDEBUG 0
|
|
+#include <utils/Log.h>
|
|
+
|
|
+//#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<mStreamNrAACChan) {
|
|
+ mIsDownmix = true;
|
|
+ } else {
|
|
+ mIsDownmix = false;
|
|
+ }
|
|
+
|
|
+ if (mIsDownmix && (mStreamNrOutChan == 1)) {
|
|
+ mIsMonoDownmix = true;
|
|
+ } else {
|
|
+ mIsMonoDownmix = false;
|
|
+ }
|
|
+
|
|
+ if (mIsDownmix && mStreamNrOutChan == 2){
|
|
+ mIsStereoDownmix = true;
|
|
+ } else {
|
|
+ mIsStereoDownmix = false;
|
|
+ }
|
|
+
|
|
+}
|
|
+
|
|
+void
|
|
+CDrcPresModeWrapper::setParam(const DRC_PRES_MODE_WRAP_PARAM param, const int value)
|
|
+{
|
|
+ switch (param) {
|
|
+ case DRC_PRES_MODE_WRAP_DESIRED_TARGET:
|
|
+ mDesTarget = value;
|
|
+ break;
|
|
+ case DRC_PRES_MODE_WRAP_DESIRED_ATT_FACTOR:
|
|
+ mDesAttFactor = value;
|
|
+ break;
|
|
+ case DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR:
|
|
+ mDesBoostFactor = value;
|
|
+ break;
|
|
+ case DRC_PRES_MODE_WRAP_DESIRED_HEAVY:
|
|
+ mDesHeavy = value;
|
|
+ break;
|
|
+ case DRC_PRES_MODE_WRAP_ENCODER_TARGET:
|
|
+ mEncoderTarget = value;
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ mDataUpdate = true;
|
|
+}
|
|
+
|
|
+void
|
|
+CDrcPresModeWrapper::update()
|
|
+{
|
|
+ // Get Data from Decoder
|
|
+ int progRefLevel = mStreamPRL;
|
|
+ int drcPresMode = mStreamDRCPresMode;
|
|
+
|
|
+ // by default, do as desired
|
|
+ int newTarget = mDesTarget;
|
|
+ int newAttFactor = mDesAttFactor;
|
|
+ int newBoostFactor = mDesBoostFactor;
|
|
+ int newHeavy = mDesHeavy;
|
|
+
|
|
+ if (mDataUpdate) {
|
|
+ // sanity check
|
|
+ if ((mDesTarget < MAX_TARGET_LEVEL) && (mDesTarget != -1)){
|
|
+ mDesTarget = MAX_TARGET_LEVEL; // limit target level to -10 dB or below
|
|
+ newTarget = MAX_TARGET_LEVEL;
|
|
+ }
|
|
+
|
|
+ if (mEncoderTarget != -1) {
|
|
+ if (mDesTarget<124) { // if target level > -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<progRefLevel) { // if target level > 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<progRefLevel) { // if target level > 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 <utils/Log.h>
|
|
+
|
|
+#include "SoftAAC2.h"
|
|
+#include <OMX_AudioExt.h>
|
|
+#include <OMX_IndexExt.h>
|
|
+
|
|
+#include <cutils/properties.h>
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/foundation/hexdump.h>
|
|
+#include <media/stagefright/MediaErrors.h>
|
|
+#include <utils/misc.h>
|
|
+
|
|
+#include <math.h>
|
|
+
|
|
+#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<class T>
|
|
+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<char *>("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<char *>("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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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 <numLoops> 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<INT_PCM *>(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<INT_PCM *>(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 <media/stagefright/omx/SimpleSoftOMXComponent.h>
|
|
+
|
|
+#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<int32_t> mBufferSizes;
|
|
+ Vector<int32_t> mDecodedSizes;
|
|
+ Vector<int64_t> 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 <log/log.h>
|
|
+#include <utils/Log.h>
|
|
+
|
|
+#include "SoftAACEncoder2.h"
|
|
+#include <OMX_AudioExt.h>
|
|
+#include <OMX_IndexExt.h>
|
|
+
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/foundation/hexdump.h>
|
|
+#include <utils/misc.h>
|
|
+
|
|
+namespace android {
|
|
+
|
|
+template<class T>
|
|
+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<char *>("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<char *>("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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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 <media/stagefright/omx/SimpleSoftOMXComponent.h>
|
|
+
|
|
+#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 <utils/Log.h>
|
|
+
|
|
+#include "SoftAMR.h"
|
|
+
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+
|
|
+namespace android {
|
|
+
|
|
+template<class T>
|
|
+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<char *>("audio/amr")
|
|
+ : const_cast<char *>("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<char *>("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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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<int16_t *>(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<size_t>(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<uint8_t *>(&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 <media/stagefright/omx/SimpleSoftOMXComponent.h>
|
|
+#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 <utils/Log.h>
|
|
+
|
|
+#include "SoftAMRNBEncoder.h"
|
|
+
|
|
+#include "gsmamr_enc.h"
|
|
+
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/foundation/hexdump.h>
|
|
+
|
|
+namespace android {
|
|
+
|
|
+static const int32_t kSampleRate = 8000;
|
|
+
|
|
+template<class T>
|
|
+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<char *>("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<char *>("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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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 <media/stagefright/omx/SimpleSoftOMXComponent.h>
|
|
+
|
|
+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 <utils/Log.h>
|
|
+
|
|
+#include "SoftAMRWBEncoder.h"
|
|
+
|
|
+#include "cmnMemory.h"
|
|
+
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/foundation/hexdump.h>
|
|
+
|
|
+namespace android {
|
|
+
|
|
+static const int32_t kSampleRate = 16000;
|
|
+
|
|
+template<class T>
|
|
+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<char *>("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<char *>("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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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 <media/stagefright/omx/SimpleSoftOMXComponent.h>
|
|
+
|
|
+#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 <utils/Log.h>
|
|
+
|
|
+#include "ih264_typedefs.h"
|
|
+#include "iv.h"
|
|
+#include "ivd.h"
|
|
+#include "ih264d.h"
|
|
+#include "SoftAVCDec.h"
|
|
+
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/MediaDefs.h>
|
|
+#include <OMX_VideoExt.h>
|
|
+#include <inttypes.h>
|
|
+
|
|
+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<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
|
|
+ List<BufferInfo *> &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 <media/stagefright/omx/SoftVideoDecoderOMXComponent.h>
|
|
+#include <sys/time.h>
|
|
+
|
|
+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 <utils/Log.h>
|
|
+#include <utils/misc.h>
|
|
+
|
|
+#include "OMX_Video.h"
|
|
+
|
|
+#include <media/hardware/HardwareAPI.h>
|
|
+#include <media/hardware/MetadataBufferType.h>
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/MediaDefs.h>
|
|
+#include <media/stagefright/MediaErrors.h>
|
|
+#include <OMX_IndexExt.h>
|
|
+#include <OMX_VideoExt.h>
|
|
+
|
|
+#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<class T>
|
|
+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<BufferInfo *> &outQueue = getPortQueue(1);
|
|
+ List<BufferInfo *> &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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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 <media/stagefright/foundation/ABase.h>
|
|
+#include <utils/Vector.h>
|
|
+
|
|
+#include <media/stagefright/omx/SoftVideoEncoderOMXComponent.h>
|
|
+
|
|
+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 <utils/Log.h>
|
|
+
|
|
+#include "SoftFlacDecoder.h"
|
|
+#include <OMX_AudioExt.h>
|
|
+#include <OMX_IndexExt.h>
|
|
+
|
|
+#include <cutils/properties.h>
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/MediaErrors.h>
|
|
+#include <utils/misc.h>
|
|
+
|
|
+namespace android {
|
|
+
|
|
+template<class T>
|
|
+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<char *>("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<char *>("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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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<void *>(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 <media/stagefright/omx/SimpleSoftOMXComponent.h>
|
|
+
|
|
+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 <android-base/macros.h>
|
|
+#include <utils/Log.h>
|
|
+
|
|
+#include "SoftFlacEncoder.h"
|
|
+#include <audio_utils/primitives.h>
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/MediaDefs.h>
|
|
+
|
|
+#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<class T>
|
|
+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<char *>("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<char *>(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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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<float *>(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<int16_t *>(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<BufferInfo *> &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 <media/stagefright/omx/SimpleSoftOMXComponent.h>
|
|
+
|
|
+#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 <utils/Log.h>
|
|
+
|
|
+#include "SoftG711.h"
|
|
+
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/MediaDefs.h>
|
|
+
|
|
+#define MAX_CHANNEL_COUNT 6 /* maximum number of audio channels that can be decoded */
|
|
+
|
|
+namespace android {
|
|
+
|
|
+template<class T>
|
|
+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<char *>(
|
|
+ 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<char *>("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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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<int16_t *>(outHeader->pBuffer),
|
|
+ inputptr, inHeader->nFilledLen);
|
|
+ } else {
|
|
+ DecodeALaw(
|
|
+ reinterpret_cast<int16_t *>(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 <media/stagefright/omx/SimpleSoftOMXComponent.h>
|
|
+
|
|
+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 <utils/Log.h>
|
|
+
|
|
+#include "SoftGSM.h"
|
|
+
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/MediaDefs.h>
|
|
+
|
|
+namespace android {
|
|
+
|
|
+template<class T>
|
|
+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<char *>(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<char *>("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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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<int16_t *>(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 <media/stagefright/omx/SimpleSoftOMXComponent.h>
|
|
+
|
|
+#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 <utils/Log.h>
|
|
+
|
|
+#include "ihevc_typedefs.h"
|
|
+#include "iv.h"
|
|
+#include "ivd.h"
|
|
+#include "ihevcd_cxa.h"
|
|
+#include "SoftHEVC.h"
|
|
+
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/foundation/AUtils.h>
|
|
+#include <media/stagefright/MediaDefs.h>
|
|
+#include <OMX_VideoExt.h>
|
|
+
|
|
+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<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
|
|
+ List<BufferInfo *> &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<android::SoftOMXComponent> 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 <media/stagefright/omx/SoftVideoDecoderOMXComponent.h>
|
|
+#include <sys/time.h>
|
|
+
|
|
+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 <utils/Log.h>
|
|
+
|
|
+#include "SoftMPEG4.h"
|
|
+
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/foundation/AUtils.h>
|
|
+#include <media/stagefright/MediaDefs.h>
|
|
+#include <media/stagefright/MediaErrors.h>
|
|
+
|
|
+#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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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<BufferInfo *>::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<BufferInfo *>::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 <media/stagefright/omx/SoftVideoDecoderOMXComponent.h>
|
|
+
|
|
+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<int32_t, OMX_TICKS> 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 <utils/Log.h>
|
|
+#include <utils/misc.h>
|
|
+
|
|
+#include "mp4enc_api.h"
|
|
+#include "OMX_Video.h"
|
|
+
|
|
+#include <media/hardware/HardwareAPI.h>
|
|
+#include <media/hardware/MetadataBufferType.h>
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/foundation/AUtils.h>
|
|
+#include <media/stagefright/MediaDefs.h>
|
|
+#include <media/stagefright/MediaErrors.h>
|
|
+#include <media/stagefright/MetaData.h>
|
|
+
|
|
+#include "SoftMPEG4Encoder.h"
|
|
+
|
|
+#include <inttypes.h>
|
|
+
|
|
+#ifndef INT32_MAX
|
|
+#define INT32_MAX 2147483647
|
|
+#endif
|
|
+
|
|
+namespace android {
|
|
+
|
|
+template<class T>
|
|
+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<BufferInfo *> &outQueue = getPortQueue(1);
|
|
+ List<BufferInfo *> &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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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 <media/stagefright/foundation/ABase.h>
|
|
+#include <media/stagefright/omx/SoftVideoEncoderOMXComponent.h>
|
|
+#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<InputBufferInfo> 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 <utils/Log.h>
|
|
+
|
|
+#include "SoftMP3.h"
|
|
+
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/MediaDefs.h>
|
|
+
|
|
+#include <pvmp3decoder_api.h>
|
|
+
|
|
+namespace android {
|
|
+
|
|
+template<class T>
|
|
+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<char *>(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<char *>("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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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<int16_t *>(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 <media/stagefright/omx/SimpleSoftOMXComponent.h>
|
|
+
|
|
+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 <utils/Log.h>
|
|
+
|
|
+#include "iv_datatypedef.h"
|
|
+#include "iv.h"
|
|
+#include "ivd.h"
|
|
+#include "impeg2d.h"
|
|
+#include "SoftMPEG2.h"
|
|
+
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/MediaDefs.h>
|
|
+#include <OMX_VideoExt.h>
|
|
+
|
|
+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<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
|
|
+ List<BufferInfo *> &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 <media/stagefright/omx/SoftVideoDecoderOMXComponent.h>
|
|
+#include <sys/time.h>
|
|
+
|
|
+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 <utils/Log.h>
|
|
+#include <utils/misc.h>
|
|
+#include "OMX_VideoExt.h"
|
|
+
|
|
+#include "SoftVPX.h"
|
|
+
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/MediaDefs.h>
|
|
+
|
|
+
|
|
+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<BufferInfo *> &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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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 <media/stagefright/omx/SoftVideoDecoderOMXComponent.h>
|
|
+
|
|
+#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<ABuffer> 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 <utils/Log.h>
|
|
+#include <utils/misc.h>
|
|
+
|
|
+#include <media/hardware/HardwareAPI.h>
|
|
+#include <media/hardware/MetadataBufferType.h>
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/MediaDefs.h>
|
|
+
|
|
+#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 <OMX_VideoExt.h>
|
|
+#include <OMX_IndexExt.h>
|
|
+
|
|
+#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 <utils/Log.h>
|
|
+#include <utils/misc.h>
|
|
+
|
|
+#include <media/hardware/HardwareAPI.h>
|
|
+#include <media/hardware/MetadataBufferType.h>
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/MediaDefs.h>
|
|
+
|
|
+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 <OMX_VideoExt.h>
|
|
+#include <OMX_IndexExt.h>
|
|
+
|
|
+#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 <android-base/macros.h>
|
|
+#include <utils/Log.h>
|
|
+#include <utils/misc.h>
|
|
+
|
|
+#include <media/hardware/HardwareAPI.h>
|
|
+#include <media/hardware/MetadataBufferType.h>
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/MediaDefs.h>
|
|
+
|
|
+#ifndef INT32_MAX
|
|
+#define INT32_MAX 2147483647
|
|
+#endif
|
|
+
|
|
+namespace android {
|
|
+
|
|
+template<class T>
|
|
+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<BufferInfo *> &inputBufferInfoQueue = getPortQueue(kInputPortIndex);
|
|
+ List<BufferInfo *> &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 <media/stagefright/omx/SoftVideoEncoderOMXComponent.h>
|
|
+
|
|
+#include <OMX_VideoExt.h>
|
|
+#include <OMX_IndexExt.h>
|
|
+
|
|
+#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 <utils/Log.h>
|
|
+
|
|
+#include "SoftOpus.h"
|
|
+#include <OMX_AudioExt.h>
|
|
+#include <OMX_IndexExt.h>
|
|
+
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/MediaDefs.h>
|
|
+
|
|
+extern "C" {
|
|
+ #include <opus.h>
|
|
+ #include <opus_multistream.h>
|
|
+}
|
|
+
|
|
+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<class T>
|
|
+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<char *>(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<char *>("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<int16_t>(
|
|
+ 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<double>(ns) * kRate / 1000000000;
|
|
+}
|
|
+
|
|
+void SoftOpus::handleEOS() {
|
|
+ List<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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<int64_t*>(inHeader->pBuffer +
|
|
+ inHeader->nOffset)),
|
|
+ kRate);
|
|
+ mSamplesToDiscard = mCodecDelay;
|
|
+ } else {
|
|
+ mSeekPreRoll = ns_to_samples(
|
|
+ *(reinterpret_cast<int64_t*>(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 <media/stagefright/omx/SimpleSoftOMXComponent.h>
|
|
+
|
|
+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 <utils/Log.h>
|
|
+
|
|
+#include "SoftRaw.h"
|
|
+
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/foundation/hexdump.h>
|
|
+
|
|
+namespace android {
|
|
+
|
|
+template<class T>
|
|
+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<char *>("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<char *>("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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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 <media/stagefright/omx/SimpleSoftOMXComponent.h>
|
|
+
|
|
+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 <utils/Log.h>
|
|
+
|
|
+#include "SoftVorbis.h"
|
|
+
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/MediaDefs.h>
|
|
+
|
|
+static int kDefaultChannelCount = 1;
|
|
+static int kDefaultSamplingRate = 48000;
|
|
+
|
|
+extern "C" {
|
|
+ #include <Tremolo/codec_internal.h>
|
|
+
|
|
+ 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<class T>
|
|
+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<char *>(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<char *>("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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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<BufferInfo *> &inQueue = getPortQueue(0);
|
|
+ List<BufferInfo *> &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 <media/stagefright/omx/SimpleSoftOMXComponent.h>
|
|
+
|
|
+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 <utils/Log.h>
|
|
+
|
|
+#include "SoftXAAC.h"
|
|
+
|
|
+#include <OMX_AudioExt.h>
|
|
+#include <OMX_IndexExt.h>
|
|
+#include <cutils/properties.h>
|
|
+#include <math.h>
|
|
+#include <media/stagefright/MediaErrors.h>
|
|
+#include <media/stagefright/foundation/ADebug.h>
|
|
+#include <media/stagefright/foundation/hexdump.h>
|
|
+#include <utils/misc.h>
|
|
+
|
|
+/* 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 <class T>
|
|
+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<char*>("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<char*>("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<BufferInfo*>& inQueue = getPortQueue(0);
|
|
+ List<BufferInfo*>& 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<signed short*>(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 <media/stagefright/omx/SimpleSoftOMXComponent.h>
|
|
+
|
|
+#include <string.h>
|
|
+#include <stdlib.h>
|
|
+#include <stdio.h>
|
|
+
|
|
+#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<void*> mMemoryVec;
|
|
+ Vector<void*> 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
|
|
|