Merge "Move Visualizer to libaudioeffect_jni, its only user"
diff --git a/media/libaudiofoundation/Android.bp b/media/libaudiofoundation/Android.bp
index e830e56..1df0d16 100644
--- a/media/libaudiofoundation/Android.bp
+++ b/media/libaudiofoundation/Android.bp
@@ -4,13 +4,11 @@
export_include_dirs: ["include"],
header_libs: [
"libaudio_system_headers",
- "libaudioclient_headers",
- "libmedia_headers",
+ "libmedia_helper_headers",
],
export_header_lib_headers: [
"libaudio_system_headers",
- "libaudioclient_headers",
- "libmedia_headers",
+ "libmedia_helper_headers",
],
}
diff --git a/media/libaudioprocessing/tests/fuzzer/Android.bp b/media/libaudioprocessing/tests/fuzzer/Android.bp
new file mode 100644
index 0000000..1df47b7
--- /dev/null
+++ b/media/libaudioprocessing/tests/fuzzer/Android.bp
@@ -0,0 +1,10 @@
+cc_fuzz {
+ name: "libaudioprocessing_resampler_fuzzer",
+ srcs: [
+ "libaudioprocessing_resampler_fuzzer.cpp",
+ ],
+ defaults: ["libaudioprocessing_test_defaults"],
+ static_libs: [
+ "libsndfile",
+ ],
+}
diff --git a/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
new file mode 100644
index 0000000..938c610
--- /dev/null
+++ b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2019 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 <android-base/macros.h>
+#include <audio_utils/primitives.h>
+#include <audio_utils/sndfile.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <math.h>
+#include <media/AudioBufferProvider.h>
+#include <media/AudioResampler.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Vector.h>
+
+#include <memory>
+
+using namespace android;
+
+const int MAX_FRAMES = 10;
+const int MIN_FREQ = 1e3;
+const int MAX_FREQ = 100e3;
+
+const AudioResampler::src_quality qualities[] = {
+ AudioResampler::DEFAULT_QUALITY,
+ AudioResampler::LOW_QUALITY,
+ AudioResampler::MED_QUALITY,
+ AudioResampler::HIGH_QUALITY,
+ AudioResampler::VERY_HIGH_QUALITY,
+ AudioResampler::DYN_LOW_QUALITY,
+ AudioResampler::DYN_MED_QUALITY,
+ AudioResampler::DYN_HIGH_QUALITY,
+};
+
+class Provider : public AudioBufferProvider {
+ const void* mAddr; // base address
+ const size_t mNumFrames; // total frames
+ const size_t mFrameSize; // size of each frame in bytes
+ size_t mNextFrame; // index of next frame to provide
+ size_t mUnrel; // number of frames not yet released
+ public:
+ Provider(const void* addr, size_t frames, size_t frameSize)
+ : mAddr(addr),
+ mNumFrames(frames),
+ mFrameSize(frameSize),
+ mNextFrame(0),
+ mUnrel(0) {}
+ status_t getNextBuffer(Buffer* buffer) override {
+ if (buffer->frameCount > mNumFrames - mNextFrame) {
+ buffer->frameCount = mNumFrames - mNextFrame;
+ }
+ mUnrel = buffer->frameCount;
+ if (buffer->frameCount > 0) {
+ buffer->raw = (char*)mAddr + mFrameSize * mNextFrame;
+ return NO_ERROR;
+ } else {
+ buffer->raw = nullptr;
+ return NOT_ENOUGH_DATA;
+ }
+ }
+ virtual void releaseBuffer(Buffer* buffer) {
+ if (buffer->frameCount > mUnrel) {
+ mNextFrame += mUnrel;
+ mUnrel = 0;
+ } else {
+ mNextFrame += buffer->frameCount;
+ mUnrel -= buffer->frameCount;
+ }
+ buffer->frameCount = 0;
+ buffer->raw = nullptr;
+ }
+ void reset() { mNextFrame = 0; }
+};
+
+audio_format_t chooseFormat(AudioResampler::src_quality quality,
+ uint8_t input_byte) {
+ switch (quality) {
+ case AudioResampler::DYN_LOW_QUALITY:
+ case AudioResampler::DYN_MED_QUALITY:
+ case AudioResampler::DYN_HIGH_QUALITY:
+ if (input_byte % 2) {
+ return AUDIO_FORMAT_PCM_FLOAT;
+ }
+ FALLTHROUGH_INTENDED;
+ default:
+ return AUDIO_FORMAT_PCM_16_BIT;
+ }
+}
+
+int parseValue(const uint8_t* src, int index, void* dst, size_t size) {
+ memcpy(dst, &src[index], size);
+ return size;
+}
+
+bool validFreq(int freq) { return freq > MIN_FREQ && freq < MAX_FREQ; }
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ int input_freq = 0;
+ int output_freq = 0;
+ int input_channels = 0;
+
+ float left_volume = 0;
+ float right_volume = 0;
+
+ size_t metadata_size = 2 + 3 * sizeof(int) + 2 * sizeof(float);
+ if (size < metadata_size) {
+ // not enough data to set options
+ return 0;
+ }
+
+ AudioResampler::src_quality quality = qualities[data[0] % 8];
+ audio_format_t format = chooseFormat(quality, data[1]);
+
+ int index = 2;
+
+ index += parseValue(data, index, &input_freq, sizeof(int));
+ index += parseValue(data, index, &output_freq, sizeof(int));
+ index += parseValue(data, index, &input_channels, sizeof(int));
+
+ index += parseValue(data, index, &left_volume, sizeof(float));
+ index += parseValue(data, index, &right_volume, sizeof(float));
+
+ if (!validFreq(input_freq) || !validFreq(output_freq)) {
+ // sampling frequencies must be reasonable
+ return 0;
+ }
+
+ if (input_channels < 1 ||
+ input_channels > (quality < AudioResampler::DYN_LOW_QUALITY ? 2 : 8)) {
+ // invalid number of input channels
+ return 0;
+ }
+
+ size_t single_channel_size =
+ format == AUDIO_FORMAT_PCM_FLOAT ? sizeof(float) : sizeof(int16_t);
+ size_t input_frame_size = single_channel_size * input_channels;
+ size_t input_size = size - metadata_size;
+ uint8_t input_data[input_size];
+ memcpy(input_data, &data[metadata_size], input_size);
+
+ size_t input_frames = input_size / input_frame_size;
+ if (input_frames > MAX_FRAMES) {
+ return 0;
+ }
+
+ Provider provider(input_data, input_frames, input_frame_size);
+
+ std::unique_ptr<AudioResampler> resampler(
+ AudioResampler::create(format, input_channels, output_freq, quality));
+
+ resampler->setSampleRate(input_freq);
+ resampler->setVolume(left_volume, right_volume);
+
+ // output is at least stereo samples
+ int output_channels = input_channels > 2 ? input_channels : 2;
+ size_t output_frame_size = output_channels * sizeof(int32_t);
+ size_t output_frames = (input_frames * output_freq) / input_freq;
+ size_t output_size = output_frames * output_frame_size;
+
+ uint8_t output_data[output_size];
+ for (size_t i = 0; i < output_frames; i++) {
+ memset(output_data, 0, output_size);
+ resampler->resample((int*)output_data, i, &provider);
+ }
+
+ return 0;
+}
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index bbf6811..3b81915 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -15,37 +15,6 @@
],
}
-cc_library {
- name: "libmedia_helper",
- vendor_available: true,
- vndk: {
- enabled: true,
- },
- double_loadable: true,
- srcs: [
- "AudioParameter.cpp",
- "TypeConverter.cpp",
- ],
- cflags: [
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wall",
- ],
- shared_libs: [
- "libutils",
- "liblog",
- ],
- header_libs: [
- "libmedia_headers",
- "libaudioclient_headers",
- "libaudio_system_headers",
- ],
- export_header_lib_headers: [
- "libmedia_headers",
- ],
- clang: true,
-}
-
filegroup {
name: "libmedia_omx_aidl",
srcs: [
diff --git a/media/libmedia/include/media/LinearMap.h b/media/libmedia/include/media/LinearMap.h
deleted file mode 100644
index 2220a0c..0000000
--- a/media/libmedia/include/media/LinearMap.h
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * 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 ANDROID_LINEAR_MAP_H
-#define ANDROID_LINEAR_MAP_H
-
-#include <stdint.h>
-
-namespace android {
-
-/*
-A general purpose lookup utility that defines a mapping between X and Y as a
-continuous set of line segments with shared (x, y) end-points.
-The (x, y) points must be added in order, monotonically increasing in both x and y;
-a log warning is emitted if this does not happen (See general usage notes below).
-
-A limited history of (x, y) points is kept for space reasons (See general usage notes).
-
-In AudioFlinger, we use the LinearMap to associate track frames to
-sink frames. When we want to obtain a client track timestamp, we first
-get a timestamp from the sink. The sink timestamp's position (mPosition)
-corresponds to the sink frames written. We use LinearMap to figure out which track frame
-the sink frame corresponds to. This allows us to substitute a track frame for the
-the sink frame (keeping the mTime identical) and return that timestamp back to the client.
-
-The method findX() can be used to retrieve an x value from a given y value and is
-used for timestamps, similarly for findY() which is provided for completeness.
-
-We update the (track frame, sink frame) points in the LinearMap each time we write data
-to the sink by the AudioFlinger PlaybackThread (MixerThread).
-
-
-AudioFlinger Timestamp Notes:
-
-1) Example: Obtaining a track timestamp during playback. In this case, the LinearMap
-looks something like this:
-
-Track Frame Sink Frame
-(track start)
-0 50000 (track starts here, the sink may already be running)
-1000 51000
-2000 52000
-
-When we request a track timestamp, we call the sink getTimestamp() and get for example
-mPosition = 51020. Using the LinearMap, we find we have played to track frame 1020.
-We substitute the sink mPosition of 51020 with the track position 1020,
-and return that timestamp to the app.
-
-2) Example: Obtaining a track timestamp duing pause. In this case, the LinearMap
-looks something like this:
-
-Track Frame Sink Frame
-... (some time has gone by)
-15000 30000
-16000 31000
-17000 32000
-(pause here)
-(suppose we call sink getTimestamp() here and get sink mPosition = 31100; that means
- we have played to track frame 16100. The track timestamp mPosition will
- continue to advance until the sink timestamp returns a value of mPosition
- greater than 32000, corresponding to track frame 17000 when the pause was called).
-17000 33000
-17000 34000
-...
-
-3) If the track underruns, it appears as if a pause was called on that track.
-
-4) If there is an underrun in the HAL layer, then it may be possible that
-the sink getTimestamp() will return a value greater than the number of frames written
-(it should always be less). This should be rare, if not impossible by some
-HAL implementations of the sink getTimestamp. In that case, timing is lost
-and we will return the most recent track frame written.
-
-5) When called with no points in the map, findX() returns the start value (default 0).
-This is consistent with starting after a stop() or flush().
-
-6) Resuming after Track standby will be similar to coming out of pause, as the HAL ensures
-framesWritten() and getTimestamp() are contiguous for non-offloaded/direct tracks.
-
-7) LinearMap works for different speeds and sample rates as it uses
-linear interpolation. Since AudioFlinger only updates speed and sample rate
-exactly at the sample points pushed into the LinearMap, the returned values
-from findX() and findY() are accurate regardless of how many speed or sample
-rate changes are made, so long as the coordinate looked up is within the
-sample history.
-
-General usage notes:
-
-1) In order for the LinearMap to work reliably, you cannot look backwards more
-than the size of its circular buffer history, set upon creation (typically 16).
-If you look back further, the position is extrapolated either from a passed in
-extrapolation parameter or from the oldest line segment.
-
-2) Points must monotonically increase in x and y. The increment between adjacent
-points cannot be greater than signed 32 bits. Wrap in the x, y coordinates are supported,
-since we use differences in our computation.
-
-3) If the frame data is discontinuous (due to stop or flush) call reset() to clear
-the sample counter.
-
-4) If (x, y) are not strictly monotonic increasing, i.e. (x2 > x1) and (y2 > y1),
-then one or both of the inverses y = f(x) or x = g(y) may have multiple solutions.
-In that case, the most recent solution is returned by findX() or findY(). We
-do not warn if (x2 == x1) or (y2 == y1), but we do logcat warn if (x2 < x1) or
-(y2 < y1).
-
-5) Due to rounding it is possible x != findX(findY(x)) or y != findY(findX(y))
-even when the inverse exists. Nevertheless, the values should be close.
-
-*/
-
-template <typename T>
-class LinearMap {
-public:
- // This enumeration describes the reliability of the findX() or findY() estimation
- // in descending order.
- enum FindMethod {
- FIND_METHOD_INTERPOLATION, // High reliability (errors due to rounding)
- FIND_METHOD_FORWARD_EXTRAPOLATION, // Reliability based on no future speed changes
- FIND_METHOD_BACKWARD_EXTRAPOLATION, // Reliability based on prior estimated speed
- FIND_METHOD_START_VALUE, // No samples in history, using start value
- };
-
- explicit LinearMap(size_t size)
- : mSize(size),
- mPos(0), // a circular buffer, so could start anywhere. the first sample is at 1.
- mSamples(0),
- // mStepValid(false), // only valid if mSamples > 1
- // mExtrapolateTail(false), // only valid if mSamples > 0
- mX(new T[size]),
- mY(new T[size]) { }
-
- ~LinearMap() {
- delete[] mX;
- delete[] mY;
- }
-
- // Add a new sample point to the linear map.
- //
- // The difference between the new sample and the previous sample
- // in the x or y coordinate must be less than INT32_MAX for purposes
- // of the linear interpolation or extrapolation.
- //
- // The value should be monotonic increasing (e.g. diff >= 0);
- // logcat warnings are issued if they are not.
- __attribute__((no_sanitize("integer")))
- void push(T x, T y) {
- // Assumption: we assume x, y are monotonic increasing values,
- // which (can) wrap in precision no less than 32 bits and have
- // "step" or differences between adjacent points less than 32 bits.
-
- if (mSamples > 0) {
- const bool lastStepValid = mStepValid;
- int32_t xdiff;
- int32_t ydiff;
- // check difference assumption here
- mStepValid = checkedDiff(&xdiff, x, mX[mPos], "x")
- & /* bitwise AND to always warn for ydiff, though logical AND is also OK */
- checkedDiff(&ydiff, y, mY[mPos], "y");
-
- // Optimization: do not add a new sample if the line segment would
- // simply extend the previous line segment. This extends the useful
- // history by removing redundant points.
- if (mSamples > 1 && mStepValid && lastStepValid) {
- const size_t prev = previousPosition();
- const int32_t xdiff2 = x - mX[prev];
- const int32_t ydiff2 = y - mY[prev];
-
- // if both current step and previous step are valid (non-negative and
- // less than INT32_MAX for precision greater than 4 bytes)
- // then the sum of the two steps is valid when the
- // int32_t difference is non-negative.
- if (xdiff2 >= 0 && ydiff2 >= 0
- && (int64_t)xdiff2 * ydiff == (int64_t)ydiff2 * xdiff) {
- // ALOGD("reusing sample! (%u, %u) sample depth %zd", x, y, mSamples);
- mX[mPos] = x;
- mY[mPos] = y;
- return;
- }
- }
- }
- if (++mPos >= mSize) {
- mPos = 0;
- }
- if (mSamples < mSize) {
- mExtrapolateTail = false;
- ++mSamples;
- } else {
- // we enable extrapolation beyond the oldest sample
- // if the sample buffers are completely full and we
- // no longer know the full history.
- mExtrapolateTail = true;
- }
- mX[mPos] = x;
- mY[mPos] = y;
- }
-
- // clear all samples from the circular array
- void reset() {
- // no need to reset mPos, we use a circular buffer.
- // computed values such as mStepValid are set after a subsequent push().
- mSamples = 0;
- }
-
- // returns true if LinearMap contains at least one sample.
- bool hasData() const {
- return mSamples != 0;
- }
-
- // find the corresponding X point from a Y point.
- // See findU for details.
- __attribute__((no_sanitize("integer")))
- T findX(T y, FindMethod *method = NULL, double extrapolation = 0.0, T startValue = 0) const {
- return findU(y, mX, mY, method, extrapolation, startValue);
- }
-
- // find the corresponding Y point from a X point.
- // See findU for details.
- __attribute__((no_sanitize("integer")))
- T findY(T x, FindMethod *method = NULL, double extrapolation = 0.0, T startValue = 0) const {
- return findU(x, mY, mX, method, extrapolation, startValue);
- }
-
-protected:
-
- // returns false if the diff is out of int32_t bounds or negative.
- __attribute__((no_sanitize("integer")))
- static inline bool checkedDiff(int32_t *diff, T x2, T x1, const char *coord) {
- if (sizeof(T) >= 8) {
- const int64_t diff64 = x2 - x1;
- *diff = (int32_t)diff64; // intentionally lose precision
- if (diff64 > INT32_MAX) {
- ALOGW("LinearMap: %s overflow diff(%lld) from %llu - %llu exceeds INT32_MAX",
- coord, (long long)diff64,
- (unsigned long long)x2, (unsigned long long)x1);
- return false;
- } else if (diff64 < 0) {
- ALOGW("LinearMap: %s negative diff(%lld) from %llu - %llu",
- coord, (long long)diff64,
- (unsigned long long)x2, (unsigned long long)x1);
- return false;
- }
- return true;
- }
- // for 32 bit integers we cannot detect overflow (it
- // shows up as a negative difference).
- *diff = x2 - x1;
- if (*diff < 0) {
- ALOGW("LinearMap: %s negative diff(%d) from %u - %u",
- coord, *diff, (unsigned)x2, (unsigned)x1);
- return false;
- }
- return true;
- }
-
- // Returns the previous position in the mSamples array
- // going backwards back steps.
- //
- // Parameters:
- // back: number of backward steps, cannot be less than zero or greater than mSamples.
- //
- __attribute__((no_sanitize("integer")))
- size_t previousPosition(ssize_t back = 1) const {
- LOG_ALWAYS_FATAL_IF(back < 0 || (size_t)back > mSamples, "Invalid back(%zd)", back);
- ssize_t position = mPos - back;
- if (position < 0) position += mSize;
- return (size_t)position;
- }
-
- // A generic implementation of finding the "other coordinate" with coordinates
- // (u, v) = (x, y) or (u, v) = (y, x).
- //
- // Parameters:
- // uArray: the u axis samples.
- // vArray: the v axis samples.
- // method: [out] how the returned value was computed.
- // extrapolation: the slope used when extrapolating from the
- // first sample value or the last sample value in the history.
- // If mExtrapolateTail is set, the slope of the last line segment
- // is used if the extrapolation parameter is zero to continue the tail of history.
- // At this time, we do not use a different value for forward extrapolation from the
- // head of history from backward extrapolation from the tail of history.
- // TODO: back extrapolation value could be stored along with mX, mY in history.
- // startValue: used only when there are no samples in history. One can detect
- // whether there are samples in history by the method hasData().
- //
- __attribute__((no_sanitize("integer")))
- T findU(T v, T *uArray, T *vArray, FindMethod *method,
- double extrapolation, T startValue) const {
- if (mSamples == 0) {
- if (method != NULL) {
- *method = FIND_METHOD_START_VALUE;
- }
- return startValue; // nothing yet
- }
- ssize_t previous = 0;
- int32_t diff = 0;
- for (ssize_t i = 0; i < (ssize_t)mSamples; ++i) {
- size_t current = previousPosition(i);
-
- // Assumption: even though the type "T" may have precision greater
- // than 32 bits, the difference between adjacent points is limited to 32 bits.
- diff = v - vArray[current];
- if (diff >= 0 ||
- (i == (ssize_t)mSamples - 1 && mExtrapolateTail && extrapolation == 0.0)) {
- // ALOGD("depth = %zd out of %zd", i, limit);
- if (i == 0) {
- if (method != NULL) {
- *method = FIND_METHOD_FORWARD_EXTRAPOLATION;
- }
- return uArray[current] + diff * extrapolation;
- }
- // interpolate / extrapolate: For this computation, we
- // must use differentials here otherwise we have inconsistent
- // values on modulo wrap. previous is always valid here since
- // i > 0. we also perform rounding with the assumption
- // that uStep, vStep, and diff are non-negative.
- int32_t uStep = uArray[previous] - uArray[current]; // non-negative
- int32_t vStep = vArray[previous] - vArray[current]; // positive
- T u = uStep <= 0 || vStep <= 0 ? // we do not permit negative ustep or vstep
- uArray[current]
- : ((int64_t)diff * uStep + (vStep >> 1)) / vStep + uArray[current];
- // ALOGD("u:%u diff:%d uStep:%d vStep:%d u_current:%d",
- // u, diff, uStep, vStep, uArray[current]);
- if (method != NULL) {
- *method = (diff >= 0) ?
- FIND_METHOD_INTERPOLATION : FIND_METHOD_BACKWARD_EXTRAPOLATION;
- }
- return u;
- }
- previous = current;
- }
- // previous is always valid here.
- if (method != NULL) {
- *method = FIND_METHOD_BACKWARD_EXTRAPOLATION;
- }
- return uArray[previous] + diff * extrapolation;
- }
-
-private:
- const size_t mSize; // Size of mX and mY arrays (history).
- size_t mPos; // Index in mX and mY of last pushed data;
- // (incremented after push) [0, mSize - 1].
- size_t mSamples; // Number of valid samples in the array [0, mSize].
- bool mStepValid; // Last sample step was valid (non-negative)
- bool mExtrapolateTail; // extrapolate tail using oldest line segment
- T * const mX; // History of X values as a circular array.
- T * const mY; // History of Y values as a circular array.
-};
-
-} // namespace android
-
-#endif // ANDROID_LINEAR_MAP_H
diff --git a/media/libmediahelper/Android.bp b/media/libmediahelper/Android.bp
new file mode 100644
index 0000000..72edeec
--- /dev/null
+++ b/media/libmediahelper/Android.bp
@@ -0,0 +1,29 @@
+cc_library_headers {
+ name: "libmedia_helper_headers",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+}
+
+cc_library {
+ name: "libmedia_helper",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ double_loadable: true,
+ srcs: ["AudioParameter.cpp", "TypeConverter.cpp"],
+ cflags: [
+ "-Werror",
+ "-Wextra",
+ "-Wall",
+ ],
+ shared_libs: ["libutils", "liblog"],
+ header_libs: [
+ "libmedia_helper_headers",
+ "libaudio_system_headers",
+ ],
+ export_header_lib_headers: [
+ "libmedia_helper_headers",
+ ],
+ clang: true,
+}
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmediahelper/AudioParameter.cpp
similarity index 100%
rename from media/libmedia/AudioParameter.cpp
rename to media/libmediahelper/AudioParameter.cpp
diff --git a/media/libmedia/TypeConverter.cpp b/media/libmediahelper/TypeConverter.cpp
similarity index 100%
rename from media/libmedia/TypeConverter.cpp
rename to media/libmediahelper/TypeConverter.cpp
diff --git a/media/libaudioclient/include/media/AudioParameter.h b/media/libmediahelper/include/media/AudioParameter.h
similarity index 100%
rename from media/libaudioclient/include/media/AudioParameter.h
rename to media/libmediahelper/include/media/AudioParameter.h
diff --git a/media/libmedia/include/media/TypeConverter.h b/media/libmediahelper/include/media/TypeConverter.h
similarity index 100%
rename from media/libmedia/include/media/TypeConverter.h
rename to media/libmediahelper/include/media/TypeConverter.h
diff --git a/media/libmedia/include/media/convert.h b/media/libmediahelper/include/media/convert.h
similarity index 100%
rename from media/libmedia/include/media/convert.h
rename to media/libmediahelper/include/media/convert.h
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index bb476b5..e504327 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -102,6 +102,10 @@
"include",
],
+ header_libs: [
+ "libmedia_helper_headers",
+ ],
+
cflags: [
"-Wno-multichar",
"-Werror",
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java
new file mode 100644
index 0000000..9db9c84
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media.benchmark.tests;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.media.benchmark.R;
+import com.android.media.benchmark.library.CodecUtils;
+import com.android.media.benchmark.library.Decoder;
+import com.android.media.benchmark.library.Encoder;
+import com.android.media.benchmark.library.Extractor;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.nio.ByteBuffer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public class EncoderTest {
+ private static final Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
+ private static final String mOutputFilePath = mContext.getString(R.string.output_file_path);
+ private static final String TAG = "EncoderTest";
+ private static final long PER_TEST_TIMEOUT_MS = 120000;
+ private static final boolean DEBUG = false;
+ private static final boolean WRITE_OUTPUT = false;
+ private static final int ENCODE_DEFAULT_FRAME_RATE = 25;
+ private static final int ENCODE_DEFAULT_BIT_RATE = 8000000 /* 8 Mbps */;
+ private static final int ENCODE_MIN_BIT_RATE = 600000 /* 600 Kbps */;
+
+ private String mInputFile;
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> inputFiles() {
+ return Arrays.asList(new Object[][]{
+ // Audio Test
+ {"bbb_44100hz_2ch_128kbps_aac_30sec.mp4"},
+ {"bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp"},
+ {"bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp"},
+ {"bbb_44100hz_2ch_600kbps_flac_30sec.mp4"},
+ {"bbb_48000hz_2ch_100kbps_opus_30sec.webm"},
+ // Video Test
+ {"crowd_1920x1080_25fps_4000kbps_vp8.webm"},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts"},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv"},
+ {"crowd_1920x1080_25fps_4000kbps_vp9.webm"},
+ {"crowd_176x144_25fps_6000kbps_mpeg4.mp4"},
+ {"crowd_176x144_25fps_6000kbps_h263.3gp"}});
+ }
+
+ public EncoderTest(String inputFileName) {
+ this.mInputFile = inputFileName;
+ }
+
+ @Test(timeout = PER_TEST_TIMEOUT_MS)
+ public void sampleEncoderTest() throws Exception {
+ int status;
+ int frameSize;
+
+ //Parameters for video
+ int width = 0;
+ int height = 0;
+ int profile = 0;
+ int level = 0;
+ int frameRate = 0;
+
+ //Parameters for audio
+ int bitRate = 0;
+ int sampleRate = 0;
+ int numChannels = 0;
+
+ File inputFile = new File(mInputFilePath + mInputFile);
+ if (inputFile.exists()) {
+ FileInputStream fileInput = new FileInputStream(inputFile);
+ FileDescriptor fileDescriptor = fileInput.getFD();
+ Extractor extractor = new Extractor();
+ int trackCount = extractor.setUpExtractor(fileDescriptor);
+ if (trackCount <= 0) {
+ Log.e(TAG, "Extraction failed. No tracks for file: " + mInputFile);
+ return;
+ }
+ ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
+ ArrayList<MediaCodec.BufferInfo> frameInfo = new ArrayList<>();
+ for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+ extractor.selectExtractorTrack(currentTrack);
+ MediaFormat format = extractor.getFormat(currentTrack);
+ // Get samples from extractor
+ int sampleSize;
+ do {
+ sampleSize = extractor.getFrameSample();
+ MediaCodec.BufferInfo bufInfo = new MediaCodec.BufferInfo();
+ MediaCodec.BufferInfo info = extractor.getBufferInfo();
+ ByteBuffer dataBuffer = ByteBuffer.allocate(info.size);
+ dataBuffer.put(extractor.getFrameBuffer().array(), 0, info.size);
+ bufInfo.set(info.offset, info.size, info.presentationTimeUs, info.flags);
+ inputBuffer.add(dataBuffer);
+ frameInfo.add(bufInfo);
+ if (DEBUG) {
+ Log.d(TAG, "Extracted bufInfo: flag = " + bufInfo.flags + " timestamp = " +
+ bufInfo.presentationTimeUs + " size = " + bufInfo.size);
+ }
+ } while (sampleSize > 0);
+
+ int tid = android.os.Process.myTid();
+ File decodedFile = new File(mContext.getFilesDir() + "/decoder_" + tid + ".out");
+ FileOutputStream decodeOutputStream = new FileOutputStream(decodedFile);
+ Decoder decoder = new Decoder();
+ decoder.setupDecoder(decodeOutputStream);
+ status = decoder.decode(inputBuffer, frameInfo, false, format, "");
+ if (status == 0) {
+ Log.i(TAG, "Decoding complete.");
+ } else {
+ Log.e(TAG, "Decode returned error. Encoding did not take place." + status);
+ return;
+ }
+ decoder.deInitCodec();
+ extractor.unselectExtractorTrack(currentTrack);
+ inputBuffer.clear();
+ frameInfo.clear();
+ if (decodeOutputStream != null) {
+ decodeOutputStream.close();
+ }
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, true);
+ if (mediaCodecs.size() <= 0) {
+ Log.e(TAG, "No suitable codecs found for file: " + mInputFile + " track : " +
+ currentTrack + " mime: " + mime);
+ return;
+ }
+ Boolean[] encodeMode = {true, false};
+ /* Encoding the decoder's output */
+ for (Boolean asyncMode : encodeMode) {
+ for (String codecName : mediaCodecs) {
+ FileOutputStream encodeOutputStream = null;
+ if (WRITE_OUTPUT) {
+ File outEncodeFile = new File(mOutputFilePath + "encoder.out");
+ if (outEncodeFile.exists()) {
+ if (!outEncodeFile.delete()) {
+ Log.e(TAG, "Unable to delete existing file" +
+ decodedFile.toString());
+ }
+ }
+ if (outEncodeFile.createNewFile()) {
+ encodeOutputStream = new FileOutputStream(outEncodeFile);
+ } else {
+ Log.e(TAG, "Unable to create file to write encoder output: " +
+ outEncodeFile.toString());
+ }
+ }
+ File rawFile =
+ new File(mContext.getFilesDir() + "/decoder_" + tid + ".out");
+ if (rawFile.exists()) {
+ if (DEBUG) {
+ Log.i(TAG, "Path of decoded input file: " + rawFile.toString());
+ }
+ FileInputStream eleStream = new FileInputStream(rawFile);
+ if (mime.startsWith("video/")) {
+ width = format.getInteger(MediaFormat.KEY_WIDTH);
+ height = format.getInteger(MediaFormat.KEY_HEIGHT);
+ if (format.containsKey(MediaFormat.KEY_FRAME_RATE)) {
+ frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
+ } else if (frameRate <= 0) {
+ frameRate = ENCODE_DEFAULT_FRAME_RATE;
+ }
+ if (format.containsKey(MediaFormat.KEY_BIT_RATE)) {
+ bitRate = format.getInteger(MediaFormat.KEY_BIT_RATE);
+ } else if (bitRate <= 0) {
+ if (mime.contains("video/3gpp") ||
+ mime.contains("video/mp4v-es")) {
+ bitRate = ENCODE_MIN_BIT_RATE;
+ } else {
+ bitRate = ENCODE_DEFAULT_BIT_RATE;
+ }
+ }
+ if (format.containsKey(MediaFormat.KEY_PROFILE)) {
+ profile = format.getInteger(MediaFormat.KEY_PROFILE);
+ }
+ if (format.containsKey(MediaFormat.KEY_PROFILE)) {
+ level = format.getInteger(MediaFormat.KEY_LEVEL);
+ }
+ } else {
+ sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
+ numChannels = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+ bitRate = sampleRate * numChannels * 16;
+ }
+ /*Setup Encode Format*/
+ MediaFormat encodeFormat;
+ if (mime.startsWith("video/")) {
+ frameSize = width * height * 3 / 2;
+ encodeFormat = MediaFormat.createVideoFormat(mime, width, height);
+ encodeFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
+ encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
+ encodeFormat.setInteger(MediaFormat.KEY_PROFILE, profile);
+ encodeFormat.setInteger(MediaFormat.KEY_LEVEL, level);
+ encodeFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
+ encodeFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, frameSize);
+ } else {
+ encodeFormat = MediaFormat
+ .createAudioFormat(mime, sampleRate, numChannels);
+ encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
+ frameSize = 4096;
+ }
+ Encoder encoder = new Encoder();
+ encoder.setupEncoder(encodeOutputStream, eleStream);
+ status = encoder.encode(codecName, encodeFormat, mime, frameRate,
+ sampleRate, frameSize, asyncMode);
+ encoder.deInitEncoder();
+ if (status == 0) {
+ encoder.dumpStatistics(mInputFile + "with " + codecName + " for " +
+ "aSyncMode = " + asyncMode, extractor.getClipDuration());
+ Log.i(TAG, "Encoding complete for file: " + mInputFile +
+ " with codec: " + codecName + " for aSyncMode = " +
+ asyncMode);
+ } else {
+ Log.e(TAG,
+ codecName + " encoder returned error " + status + " for " +
+ "file:" + " " + mInputFile);
+ }
+ encoder.resetEncoder();
+ eleStream.close();
+ if (encodeOutputStream != null) {
+ encodeOutputStream.close();
+ }
+ }
+ }
+ }
+ //Cleanup temporary input file
+ if (decodedFile.exists()) {
+ if (decodedFile.delete()) {
+ Log.i(TAG, "Successfully deleted decoded file");
+ } else {
+ Log.e(TAG, "Unable to delete decoded file");
+ }
+ }
+ }
+ extractor.deinitExtractor();
+ fileInput.close();
+ } else {
+ Log.w(TAG, "Warning: Test Skipped. Cannot find " + mInputFile + " in directory " +
+ mInputFilePath);
+ }
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
new file mode 100644
index 0000000..03db294
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media.benchmark.library;
+
+import android.media.MediaCodec;
+import android.media.MediaCodec.CodecException;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class Encoder {
+ private static final int ENCODE_DEFAULT_MAX_INPUT_SIZE = 3840;
+ private static final String TAG = "Encoder";
+ private static final boolean DEBUG = false;
+ private static final int kQueueDequeueTimeoutUs = 1000;
+
+ private final Object mLock = new Object();
+ private MediaCodec mCodec;
+ private String mMime;
+ private Stats mStats;
+
+ private int mOffset;
+ private int mFrameSize;
+ private int mNumInputFrame;
+ private int mNumFrames;
+ private int mFrameRate;
+ private int mSampleRate;
+ private long mInputBufferSize;
+
+ private boolean mSawInputEOS;
+ private boolean mSawOutputEOS;
+ private boolean mSignalledError;
+
+ private FileInputStream mInputStream;
+ private FileOutputStream mOutputStream;
+
+ public Encoder() {
+ mStats = new Stats();
+ mNumInputFrame = 0;
+ mSawInputEOS = false;
+ mSawOutputEOS = false;
+ mSignalledError = false;
+ }
+
+ /**
+ * Setup of encoder
+ *
+ * @param encoderOutputStream Will dump the encoder output in this stream if not null.
+ * @param fileInputStream Will read the decoded output from this stream
+ */
+ public void setupEncoder(FileOutputStream encoderOutputStream,
+ FileInputStream fileInputStream) {
+ this.mInputStream = fileInputStream;
+ this.mOutputStream = encoderOutputStream;
+ }
+
+ private MediaCodec createCodec(String codecName, String mime) throws IOException {
+ try {
+ MediaCodec codec;
+ if (codecName.isEmpty()) {
+ Log.i(TAG, "Mime type: " + mime);
+ if (mime != null) {
+ codec = MediaCodec.createEncoderByType(mime);
+ Log.i(TAG, "Encoder created for mime type " + mime);
+ return codec;
+ } else {
+ Log.e(TAG, "Mime type is null, please specify a mime type to create encoder");
+ return null;
+ }
+ } else {
+ codec = MediaCodec.createByCodecName(codecName);
+ Log.i(TAG, "Encoder created with codec name: " + codecName + " and mime: " + mime);
+ return codec;
+ }
+ } catch (IllegalArgumentException ex) {
+ ex.printStackTrace();
+ Log.e(TAG, "Failed to create encoder for " + codecName + " mime: " + mime);
+ return null;
+ }
+ }
+
+ /**
+ * Encodes the given raw input file and measures the performance of encode operation,
+ * provided a valid list of parameters are passed as inputs.
+ *
+ * @param codecName Will create the encoder with codecName
+ * @param mime For creating encode format
+ * @param encodeFormat Format of the output data
+ * @param frameSize Size of the frame
+ * @param asyncMode Will run on async implementation if true
+ * @return 0 if encode was successful , -1 for fail, -2 for encoder not created
+ * @throws IOException If the codec cannot be created.
+ */
+ public int encode(String codecName, MediaFormat encodeFormat, String mime, int frameRate,
+ int sampleRate, int frameSize, boolean asyncMode) throws IOException {
+ mInputBufferSize = mInputStream.getChannel().size();
+ mMime = mime;
+ mOffset = 0;
+ mFrameRate = frameRate;
+ mSampleRate = sampleRate;
+ long sTime = mStats.getCurTime();
+ mCodec = createCodec(codecName, mime);
+ if (mCodec == null) {
+ return -2;
+ }
+ /*Configure Codec*/
+ try {
+ mCodec.configure(encodeFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+ } catch (IllegalArgumentException | IllegalStateException | MediaCodec.CryptoException e) {
+ Log.e(TAG, "Failed to configure " + mCodec.getName() + " encoder.");
+ e.printStackTrace();
+ return -2;
+ }
+ if (mMime.startsWith("video/")) {
+ mFrameSize = frameSize;
+ } else {
+ int maxInputSize = ENCODE_DEFAULT_MAX_INPUT_SIZE;
+ MediaFormat format = mCodec.getInputFormat();
+ if (format.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) {
+ maxInputSize = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
+ }
+ mFrameSize = frameSize;
+ if (mFrameSize > maxInputSize && maxInputSize > 0) {
+ mFrameSize = maxInputSize;
+ }
+ }
+ mNumFrames = (int) ((mInputBufferSize + mFrameSize - 1) / mFrameSize);
+ if (asyncMode) {
+ mCodec.setCallback(new MediaCodec.Callback() {
+ @Override
+ public void onInputBufferAvailable(@NonNull MediaCodec mediaCodec,
+ int inputBufferId) {
+ try {
+ mStats.addInputTime();
+ onInputAvailable(mediaCodec, inputBufferId);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, e.toString());
+ }
+ }
+
+ @Override
+ public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec,
+ int outputBufferId,
+ @NonNull MediaCodec.BufferInfo bufferInfo) {
+ mStats.addOutputTime();
+ onOutputAvailable(mediaCodec, outputBufferId, bufferInfo);
+ if (mSawOutputEOS) {
+ Log.i(TAG, "Saw output EOS");
+ synchronized (mLock) { mLock.notify(); }
+ }
+ }
+
+ @Override
+ public void onError(@NonNull MediaCodec mediaCodec, @NonNull CodecException e) {
+ mediaCodec.stop();
+ mediaCodec.release();
+ Log.e(TAG, "CodecError: " + e.toString());
+ e.printStackTrace();
+ }
+
+ @Override
+ public void onOutputFormatChanged(@NonNull MediaCodec mediaCodec,
+ @NonNull MediaFormat format) {
+ Log.i(TAG, "Output format changed. Format: " + format.toString());
+ }
+ });
+ }
+ mCodec.start();
+ long eTime = mStats.getCurTime();
+ mStats.setInitTime(mStats.getTimeDiff(sTime, eTime));
+ mStats.setStartTime();
+ if (asyncMode) {
+ try {
+ synchronized (mLock) { mLock.wait(); }
+ if (mSignalledError) {
+ return -1;
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ } else {
+ while (!mSawOutputEOS && !mSignalledError) {
+ /* Queue input data */
+ if (!mSawInputEOS) {
+ int inputBufferId = mCodec.dequeueInputBuffer(kQueueDequeueTimeoutUs);
+ if (inputBufferId < 0 && inputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ Log.e(TAG, "MediaCodec.dequeueInputBuffer " + "returned invalid index : " +
+ inputBufferId);
+ return -1;
+ }
+ mStats.addInputTime();
+ onInputAvailable(mCodec, inputBufferId);
+ }
+ /* Dequeue output data */
+ MediaCodec.BufferInfo outputBufferInfo = new MediaCodec.BufferInfo();
+ int outputBufferId =
+ mCodec.dequeueOutputBuffer(outputBufferInfo, kQueueDequeueTimeoutUs);
+ if (outputBufferId < 0) {
+ if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ MediaFormat outFormat = mCodec.getOutputFormat();
+ Log.i(TAG, "Output format changed. Format: " + outFormat.toString());
+ } else if (outputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ Log.e(TAG, "MediaCodec.dequeueOutputBuffer" + " returned invalid index " +
+ outputBufferId);
+ return -1;
+ }
+ } else {
+ mStats.addOutputTime();
+ if (DEBUG) {
+ Log.d(TAG, "Dequeue O/P buffer with BufferID " + outputBufferId);
+ }
+ onOutputAvailable(mCodec, outputBufferId, outputBufferInfo);
+ }
+ }
+ }
+ return 0;
+ }
+
+ private void onOutputAvailable(MediaCodec mediaCodec, int outputBufferId,
+ MediaCodec.BufferInfo outputBufferInfo) {
+ if (mSawOutputEOS || outputBufferId < 0) {
+ if (mSawOutputEOS) {
+ Log.i(TAG, "Saw output EOS");
+ }
+ return;
+ }
+ ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferId);
+ if (mOutputStream != null) {
+ try {
+
+ byte[] bytesOutput = new byte[outputBuffer.remaining()];
+ outputBuffer.get(bytesOutput);
+ mOutputStream.write(bytesOutput);
+ } catch (IOException e) {
+ e.printStackTrace();
+ Log.d(TAG, "Error Dumping File: Exception " + e.toString());
+ return;
+ }
+ }
+ mStats.addFrameSize(outputBuffer.remaining());
+ mediaCodec.releaseOutputBuffer(outputBufferId, false);
+ mSawOutputEOS = (outputBufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+ }
+
+ private void onInputAvailable(MediaCodec mediaCodec, int inputBufferId) throws IOException {
+ if (mSawOutputEOS || inputBufferId < 0) {
+ if (mSawOutputEOS) {
+ Log.i(TAG, "Saw input EOS");
+ }
+ return;
+ }
+ if (mInputBufferSize < mOffset) {
+ Log.e(TAG, "Out of bound access of input buffer");
+ mSignalledError = true;
+ return;
+ }
+ ByteBuffer inputBuffer = mCodec.getInputBuffer(inputBufferId);
+ if (inputBuffer == null) {
+ mSignalledError = true;
+ return;
+ }
+ int bufSize = inputBuffer.capacity();
+ int bytesRead = mFrameSize;
+ if (mInputBufferSize - mOffset < mFrameSize) {
+ bytesRead = (int) (mInputBufferSize - mOffset);
+ }
+ if (bufSize < bytesRead) {
+ mSignalledError = true;
+ return;
+ }
+ byte[] inputArray = new byte[bytesRead];
+ mInputStream.read(inputArray, 0, bytesRead);
+ inputBuffer.put(inputArray);
+ int flag = 0;
+ if (mNumInputFrame >= mNumFrames - 1 || bytesRead == 0) {
+ Log.i(TAG, "Sending EOS on input last frame");
+ mSawInputEOS = true;
+ flag = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+ }
+ int presentationTimeUs;
+ if (mMime.startsWith("video/")) {
+ presentationTimeUs = mNumInputFrame * (1000000 / mFrameRate);
+ } else {
+ presentationTimeUs = mNumInputFrame * mFrameSize * 1000000 / mSampleRate;
+ }
+ mediaCodec.queueInputBuffer(inputBufferId, 0, bytesRead, presentationTimeUs, flag);
+ mNumInputFrame++;
+ mOffset += bytesRead;
+ }
+
+ /**
+ * Stops the codec and releases codec resources.
+ */
+ public void deInitEncoder() {
+ long sTime = mStats.getCurTime();
+ if (mCodec != null) {
+ mCodec.stop();
+ mCodec.release();
+ mCodec = null;
+ }
+ long eTime = mStats.getCurTime();
+ mStats.setDeInitTime(mStats.getTimeDiff(sTime, eTime));
+ }
+
+ /**
+ * Prints out the statistics in the information log
+ *
+ * @param inputReference The operation being performed, in this case encode
+ * @param durationUs Duration of the clip in microseconds
+ */
+ public void dumpStatistics(String inputReference, long durationUs) {
+ String operation = "encode";
+ mStats.dumpStatistics(operation, inputReference, durationUs);
+ }
+
+ /**
+ * Resets the stats
+ */
+ public void resetEncoder() {
+ mOffset = 0;
+ mInputBufferSize = 0;
+ mNumInputFrame = 0;
+ mSawInputEOS = false;
+ mSawOutputEOS = false;
+ mSignalledError = false;
+ mStats.reset();
+ }
+}
diff --git a/media/tests/benchmark/README.md b/media/tests/benchmark/README.md
index 1c1ef4f..487ddb8 100644
--- a/media/tests/benchmark/README.md
+++ b/media/tests/benchmark/README.md
@@ -99,7 +99,6 @@
adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.ExtractorTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
```
-
## Decoder
The test decodes input stream and benchmarks the decoders available in SDK.
@@ -107,11 +106,17 @@
adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.DecoderTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
```
-
## Muxer
The test muxes elementary stream and benchmarks different writers available in SDK.
```
adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.MuxerTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+```
+
+## Encoder
+
+The test encodes input stream and benchmarks the encoders available in SDK.
+```
+adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.EncoderTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
```
diff --git a/media/tests/benchmark/src/native/common/Android.bp b/media/tests/benchmark/src/native/common/Android.bp
index e163738..1da0102 100644
--- a/media/tests/benchmark/src/native/common/Android.bp
+++ b/media/tests/benchmark/src/native/common/Android.bp
@@ -15,10 +15,10 @@
*/
cc_library_static {
- name: "libbenchmark_common",
+ name: "libmediabenchmark_common",
defaults: [
- "libbenchmark-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: [
@@ -32,19 +32,19 @@
}
cc_defaults {
- name: "libbenchmark_common-defaults",
+ name: "libmediabenchmark_common-defaults",
defaults: [
- "libbenchmark-defaults",
+ "libmediabenchmark-defaults",
],
static_libs: [
- "libbenchmark_common",
+ "libmediabenchmark_common",
],
}
cc_defaults {
- name: "libbenchmark-defaults",
+ name: "libmediabenchmark-defaults",
shared_libs: [
"libmediandk",
@@ -61,7 +61,7 @@
// public dependency for native implementation
// to be used by code under media/benchmark/* only
cc_defaults {
- name: "libbenchmark_soft_sanitize_all-defaults",
+ name: "libmediabenchmark_soft_sanitize_all-defaults",
sanitize: {
misc_undefined: [
diff --git a/media/tests/benchmark/src/native/decoder/Android.bp b/media/tests/benchmark/src/native/decoder/Android.bp
index f2d3db5..b6286d4 100644
--- a/media/tests/benchmark/src/native/decoder/Android.bp
+++ b/media/tests/benchmark/src/native/decoder/Android.bp
@@ -15,15 +15,15 @@
*/
cc_library_static {
- name: "libbenchmark_decoder",
+ name: "libmediabenchmark_decoder",
defaults: [
- "libbenchmark_common-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: ["Decoder.cpp"],
- static_libs: ["libbenchmark_extractor"],
+ static_libs: ["libmediabenchmark_extractor"],
export_include_dirs: ["."],
diff --git a/media/tests/benchmark/src/native/encoder/Android.bp b/media/tests/benchmark/src/native/encoder/Android.bp
index c14c319..239f378 100644
--- a/media/tests/benchmark/src/native/encoder/Android.bp
+++ b/media/tests/benchmark/src/native/encoder/Android.bp
@@ -15,16 +15,16 @@
*/
cc_library_static {
- name: "libbenchmark_encoder",
+ name: "libmediabenchmark_encoder",
defaults: [
- "libbenchmark_common-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: ["Encoder.cpp"],
- static_libs: ["libbenchmark_extractor",
- "libbenchmark_decoder",
+ static_libs: ["libmediabenchmark_extractor",
+ "libmediabenchmark_decoder",
],
export_include_dirs: ["."],
diff --git a/media/tests/benchmark/src/native/extractor/Android.bp b/media/tests/benchmark/src/native/extractor/Android.bp
index 2fbe4e8..dfd0d49 100644
--- a/media/tests/benchmark/src/native/extractor/Android.bp
+++ b/media/tests/benchmark/src/native/extractor/Android.bp
@@ -15,10 +15,10 @@
*/
cc_library_static {
- name: "libbenchmark_extractor",
+ name: "libmediabenchmark_extractor",
defaults: [
- "libbenchmark_common-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: ["Extractor.cpp"],
diff --git a/media/tests/benchmark/src/native/muxer/Android.bp b/media/tests/benchmark/src/native/muxer/Android.bp
index 6ef2a2e..f669d4a 100644
--- a/media/tests/benchmark/src/native/muxer/Android.bp
+++ b/media/tests/benchmark/src/native/muxer/Android.bp
@@ -15,15 +15,15 @@
*/
cc_library_static {
- name: "libbenchmark_muxer",
+ name: "libmediabenchmark_muxer",
defaults: [
- "libbenchmark_common-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: ["Muxer.cpp"],
- static_libs: ["libbenchmark_extractor"],
+ static_libs: ["libmediabenchmark_extractor"],
export_include_dirs: ["."],
diff --git a/media/tests/benchmark/tests/Android.bp b/media/tests/benchmark/tests/Android.bp
index fc21ef7..24fd68c 100644
--- a/media/tests/benchmark/tests/Android.bp
+++ b/media/tests/benchmark/tests/Android.bp
@@ -18,28 +18,28 @@
name: "extractorTest",
gtest: true,
defaults: [
- "libbenchmark_common-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: ["ExtractorTest.cpp"],
- static_libs: ["libbenchmark_extractor"]
+ static_libs: ["libmediabenchmark_extractor"]
}
cc_test {
name: "decoderTest",
gtest: true,
defaults: [
- "libbenchmark_common-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: ["DecoderTest.cpp"],
static_libs: [
- "libbenchmark_extractor",
- "libbenchmark_decoder",
+ "libmediabenchmark_extractor",
+ "libmediabenchmark_decoder",
],
}
@@ -47,15 +47,15 @@
name: "muxerTest",
gtest: true,
defaults: [
- "libbenchmark_common-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: ["MuxerTest.cpp"],
static_libs: [
- "libbenchmark_extractor",
- "libbenchmark_muxer",
+ "libmediabenchmark_extractor",
+ "libmediabenchmark_muxer",
],
}
@@ -63,15 +63,15 @@
name: "encoderTest",
gtest: true,
defaults: [
- "libbenchmark_common-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: ["EncoderTest.cpp"],
static_libs: [
- "libbenchmark_extractor",
- "libbenchmark_decoder",
- "libbenchmark_encoder",
+ "libmediabenchmark_extractor",
+ "libmediabenchmark_decoder",
+ "libmediabenchmark_encoder",
],
}
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 96ad54b..d50a556 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -60,6 +60,10 @@
"libsndfile",
],
+ header_libs: [
+ "libmedia_headers",
+ ],
+
cflags: [
"-DSTATE_QUEUE_INSTANTIATIONS=\"StateQueueInstantiations.cpp\"",
"-fvisibility=hidden",
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index bbf8a29..d2de5fe 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -67,11 +67,11 @@
#include <media/AudioBufferProvider.h>
#include <media/AudioMixer.h>
#include <media/ExtendedAudioBufferProvider.h>
-#include <media/LinearMap.h>
#include <media/VolumeShaper.h>
#include <audio_utils/clock.h>
#include <audio_utils/FdToString.h>
+#include <audio_utils/LinearMap.h>
#include <audio_utils/SimpleLog.h>
#include <audio_utils/TimestampVerifier.h>
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index d93d26f..08fb153 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -2032,6 +2032,15 @@
}
}
+ for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
+ auto ret = mCompositeStreamMap.valueAt(i)->deleteInternalStreams();
+ if (ret != OK) {
+ ALOGE("%s: Failed removing composite stream %s (%d)", __FUNCTION__,
+ strerror(-ret), ret);
+ }
+ }
+ mCompositeStreamMap.clear();
+
Camera2ClientBase::detachDevice();
}
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 608521a..7ed4c3d 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -1187,7 +1187,7 @@
}
sp<provider::V2_4::ICameraProvider> interface;
- interface = mServiceProxy->getService(newProvider);
+ interface = mServiceProxy->tryGetService(newProvider);
if (interface == nullptr) {
ALOGE("%s: Camera provider HAL '%s' is not actually available", __FUNCTION__,
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 4112711..2ef1f6f 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -96,6 +96,10 @@
const std::string &serviceName,
const sp<hidl::manager::V1_0::IServiceNotification>
¬ification) = 0;
+ // Will not wait for service to start if it's not already running
+ virtual sp<hardware::camera::provider::V2_4::ICameraProvider> tryGetService(
+ const std::string &serviceName) = 0;
+ // Will block for service if it exists but isn't running
virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
const std::string &serviceName) = 0;
virtual hardware::hidl_vec<hardware::hidl_string> listServices() = 0;
@@ -112,6 +116,10 @@
return hardware::camera::provider::V2_4::ICameraProvider::registerForNotifications(
serviceName, notification);
}
+ virtual sp<hardware::camera::provider::V2_4::ICameraProvider> tryGetService(
+ const std::string &serviceName) override {
+ return hardware::camera::provider::V2_4::ICameraProvider::tryGetService(serviceName);
+ }
virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
const std::string &serviceName) override {
return hardware::camera::provider::V2_4::ICameraProvider::getService(serviceName);
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index 78d737d..084dc62 100644
--- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
@@ -183,6 +183,7 @@
sp<TestICameraProvider> mTestCameraProvider;
TestInteractionProxy() {}
+
void setProvider(sp<TestICameraProvider> provider) {
mTestCameraProvider = provider;
}
@@ -199,13 +200,31 @@
return true;
}
+ virtual sp<hardware::camera::provider::V2_4::ICameraProvider> tryGetService(
+ const std::string &serviceName) override {
+ // If no provider has been given, act like the HAL isn't available and return null.
+ if (mTestCameraProvider == nullptr) return nullptr;
+ return getService(serviceName);
+ }
+
virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
const std::string &serviceName) override {
+ // If no provider has been given, fail; in reality, getService would
+ // block for HALs that don't start correctly, so we should never use
+ // getService when we don't have a valid HAL running
+ if (mTestCameraProvider == nullptr) {
+ ADD_FAILURE() << "getService called with no valid provider; would block indefinitely";
+ // Real getService would block, but that's bad in unit tests. So
+ // just record an error and return nullptr
+ return nullptr;
+ }
mLastRequestedServiceNames.push_back(serviceName);
return mTestCameraProvider;
}
virtual hardware::hidl_vec<hardware::hidl_string> listServices() override {
+ // Always provide a list even if there's no actual provider yet, to
+ // simulate stuck HAL situations as well
hardware::hidl_vec<hardware::hidl_string> ret = {"test/0"};
return ret;
}
@@ -438,3 +457,52 @@
<< "Unable to change device state";
}
+
+// Test that CameraProviderManager doesn't get stuck when the camera HAL isn't really working
+TEST(CameraProviderManagerTest, BadHalStartupTest) {
+
+ std::vector<hardware::hidl_string> deviceNames;
+ deviceNames.push_back("device@3.2/test/0");
+ deviceNames.push_back("device@1.0/test/0");
+ deviceNames.push_back("device@3.2/test/1");
+ hardware::hidl_vec<common::V1_0::VendorTagSection> vendorSection;
+ status_t res;
+
+ sp<CameraProviderManager> providerManager = new CameraProviderManager();
+ sp<TestStatusListener> statusListener = new TestStatusListener();
+ TestInteractionProxy serviceProxy;
+ sp<TestICameraProvider> provider = new TestICameraProvider(deviceNames,
+ vendorSection);
+
+ // Not setting up provider in the service proxy yet, to test cases where a
+ // HAL isn't starting right
+ res = providerManager->initialize(statusListener, &serviceProxy);
+ ASSERT_EQ(res, OK) << "Unable to initialize provider manager";
+
+ // Now set up provider and trigger a registration
+ serviceProxy.setProvider(provider);
+ int numProviders = static_cast<int>(serviceProxy.listServices().size());
+
+ hardware::hidl_string testProviderFqInterfaceName =
+ "android.hardware.camera.provider@2.4::ICameraProvider";
+ hardware::hidl_string testProviderInstanceName = "test/0";
+ serviceProxy.mManagerNotificationInterface->onRegistration(
+ testProviderFqInterfaceName,
+ testProviderInstanceName, false);
+
+ // Check that new provider is called once for all the init methods
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::SET_CALLBACK], numProviders) <<
+ "Only one call to setCallback per provider expected during register";
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_VENDOR_TAGS], numProviders) <<
+ "Only one call to getVendorTags per provider expected during register";
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::IS_SET_TORCH_MODE_SUPPORTED],
+ numProviders) <<
+ "Only one call to isSetTorchModeSupported per provider expected during init";
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_CAMERA_ID_LIST], numProviders) <<
+ "Only one call to getCameraIdList per provider expected during init";
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::NOTIFY_DEVICE_STATE], numProviders) <<
+ "Only one call to notifyDeviceState per provider expected during init";
+
+ ASSERT_EQ(serviceProxy.mLastRequestedServiceNames.back(), testProviderInstanceName) <<
+ "Incorrect instance requested from service manager";
+}
diff --git a/services/mediaanalytics/statsd_audiopolicy.cpp b/services/mediaanalytics/statsd_audiopolicy.cpp
index 06c4dde..95cb274 100644
--- a/services/mediaanalytics/statsd_audiopolicy.cpp
+++ b/services/mediaanalytics/statsd_audiopolicy.cpp
@@ -60,14 +60,14 @@
metrics_proto.set_status(status);
}
//string char kAudioPolicyRqstSrc[] = "android.media.audiopolicy.rqst.src";
- char *rqst_src = NULL;
- if (item->getCString("android.media.audiopolicy.rqst.src", &rqst_src)) {
- metrics_proto.set_request_source(rqst_src);
+ std::string rqst_src;
+ if (item->getString("android.media.audiopolicy.rqst.src", &rqst_src)) {
+ metrics_proto.set_request_source(std::move(rqst_src));
}
//string char kAudioPolicyRqstPkg[] = "android.media.audiopolicy.rqst.pkg";
- char *rqst_pkg = NULL;
- if (item->getCString("android.media.audiopolicy.rqst.pkg", &rqst_pkg)) {
- metrics_proto.set_request_package(rqst_pkg);
+ std::string rqst_pkg;
+ if (item->getString("android.media.audiopolicy.rqst.pkg", &rqst_pkg)) {
+ metrics_proto.set_request_package(std::move(rqst_pkg));
}
//int32 char kAudioPolicyRqstSession[] = "android.media.audiopolicy.rqst.session";
int32_t rqst_session = -1;
@@ -75,20 +75,20 @@
metrics_proto.set_request_session(rqst_session);
}
//string char kAudioPolicyRqstDevice[] = "android.media.audiopolicy.rqst.device";
- char *rqst_device = NULL;
- if (item->getCString("android.media.audiopolicy.rqst.device", &rqst_device)) {
- metrics_proto.set_request_device(rqst_device);
+ std::string rqst_device;
+ if (item->getString("android.media.audiopolicy.rqst.device", &rqst_device)) {
+ metrics_proto.set_request_device(std::move(rqst_device));
}
//string char kAudioPolicyActiveSrc[] = "android.media.audiopolicy.active.src";
- char *active_src = NULL;
- if (item->getCString("android.media.audiopolicy.active.src", &active_src)) {
- metrics_proto.set_active_source(active_src);
+ std::string active_src;
+ if (item->getString("android.media.audiopolicy.active.src", &active_src)) {
+ metrics_proto.set_active_source(std::move(active_src));
}
//string char kAudioPolicyActivePkg[] = "android.media.audiopolicy.active.pkg";
- char *active_pkg = NULL;
- if (item->getCString("android.media.audiopolicy.active.pkg", &active_pkg)) {
- metrics_proto.set_active_package(active_pkg);
+ std::string active_pkg;
+ if (item->getString("android.media.audiopolicy.active.pkg", &active_pkg)) {
+ metrics_proto.set_active_package(std::move(active_pkg));
}
//int32 char kAudioPolicyActiveSession[] = "android.media.audiopolicy.active.session";
int32_t active_session = -1;
@@ -96,9 +96,9 @@
metrics_proto.set_active_session(active_session);
}
//string char kAudioPolicyActiveDevice[] = "android.media.audiopolicy.active.device";
- char *active_device = NULL;
- if (item->getCString("android.media.audiopolicy.active.device", &active_device)) {
- metrics_proto.set_active_device(active_device);
+ std::string active_device;
+ if (item->getString("android.media.audiopolicy.active.device", &active_device)) {
+ metrics_proto.set_active_device(std::move(active_device));
}
@@ -119,14 +119,6 @@
ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
}
- // must free the strings that we were given
- free(rqst_src);
- free(rqst_pkg);
- free(rqst_device);
- free(active_src);
- free(active_pkg);
- free(active_device);
-
return true;
}
diff --git a/services/mediaanalytics/statsd_audiorecord.cpp b/services/mediaanalytics/statsd_audiorecord.cpp
index c9edb27..7c7a62c 100644
--- a/services/mediaanalytics/statsd_audiorecord.cpp
+++ b/services/mediaanalytics/statsd_audiorecord.cpp
@@ -54,14 +54,14 @@
// flesh out the protobuf we'll hand off with our data
//
- char *encoding = NULL;
- if (item->getCString("android.media.audiorecord.encoding", &encoding)) {
- metrics_proto.set_encoding(encoding);
+ std::string encoding;
+ if (item->getString("android.media.audiorecord.encoding", &encoding)) {
+ metrics_proto.set_encoding(std::move(encoding));
}
- char *source = NULL;
- if (item->getCString("android.media.audiorecord.source", &source)) {
- metrics_proto.set_source(source);
+ std::string source;
+ if (item->getString("android.media.audiorecord.source", &source)) {
+ metrics_proto.set_source(std::move(source));
}
int32_t latency = -1;
@@ -101,11 +101,11 @@
metrics_proto.set_error_code(errcode);
}
- char *errfunc = NULL;
- if (item->getCString("android.media.audiorecord.errfunc", &errfunc)) {
- metrics_proto.set_error_function(errfunc);
- } else if (item->getCString("android.media.audiorecord.lastError.at", &errfunc)) {
- metrics_proto.set_error_function(errfunc);
+ std::string errfunc;
+ if (item->getString("android.media.audiorecord.errfunc", &errfunc)) {
+ metrics_proto.set_error_function(std::move(errfunc));
+ } else if (item->getString("android.media.audiorecord.lastError.at", &errfunc)) {
+ metrics_proto.set_error_function(std::move(errfunc));
}
// portId (int32)
@@ -119,9 +119,9 @@
metrics_proto.set_frame_count(frameCount);
}
// attributes (string)
- char *attributes = NULL;
- if (item->getCString("android.media.audiorecord.attributes", &attributes)) {
- metrics_proto.set_attributes(attributes);
+ std::string attributes;
+ if (item->getString("android.media.audiorecord.attributes", &attributes)) {
+ metrics_proto.set_attributes(std::move(attributes));
}
// channelMask (int64)
int64_t channelMask = -1;
@@ -152,12 +152,6 @@
ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
}
- // must free the strings that we were given
- free(encoding);
- free(source);
- free(errfunc);
- free(attributes);
-
return true;
}
diff --git a/services/mediaanalytics/statsd_audiothread.cpp b/services/mediaanalytics/statsd_audiothread.cpp
index 8232424..e9d6b17 100644
--- a/services/mediaanalytics/statsd_audiothread.cpp
+++ b/services/mediaanalytics/statsd_audiothread.cpp
@@ -56,9 +56,9 @@
// flesh out the protobuf we'll hand off with our data
//
- char *mytype = NULL;
- if (item->getCString(MM_PREFIX "type", &mytype)) {
- metrics_proto.set_type(mytype);
+ std::string mytype;
+ if (item->getString(MM_PREFIX "type", &mytype)) {
+ metrics_proto.set_type(std::move(mytype));
}
int32_t framecount = -1;
if (item->getInt32(MM_PREFIX "framecount", &framecount)) {
@@ -68,17 +68,17 @@
if (item->getInt32(MM_PREFIX "samplerate", &samplerate)) {
metrics_proto.set_samplerate(samplerate);
}
- char *workhist = NULL;
- if (item->getCString(MM_PREFIX "workMs.hist", &workhist)) {
- metrics_proto.set_work_millis_hist(workhist);
+ std::string workhist;
+ if (item->getString(MM_PREFIX "workMs.hist", &workhist)) {
+ metrics_proto.set_work_millis_hist(std::move(workhist));
}
- char *latencyhist = NULL;
- if (item->getCString(MM_PREFIX "latencyMs.hist", &latencyhist)) {
- metrics_proto.set_latency_millis_hist(latencyhist);
+ std::string latencyhist;
+ if (item->getString(MM_PREFIX "latencyMs.hist", &latencyhist)) {
+ metrics_proto.set_latency_millis_hist(std::move(latencyhist));
}
- char *warmuphist = NULL;
- if (item->getCString(MM_PREFIX "warmupMs.hist", &warmuphist)) {
- metrics_proto.set_warmup_millis_hist(warmuphist);
+ std::string warmuphist;
+ if (item->getString(MM_PREFIX "warmupMs.hist", &warmuphist)) {
+ metrics_proto.set_warmup_millis_hist(std::move(warmuphist));
}
int64_t underruns = -1;
if (item->getInt64(MM_PREFIX "underruns", &underruns)) {
@@ -108,9 +108,9 @@
metrics_proto.set_port_id(port_id);
}
// item->setCString(MM_PREFIX "type", threadTypeToString(mType));
- char *type = NULL;
- if (item->getCString(MM_PREFIX "type", &type)) {
- metrics_proto.set_type(type);
+ std::string type;
+ if (item->getString(MM_PREFIX "type", &type)) {
+ metrics_proto.set_type(std::move(type));
}
// item->setInt32(MM_PREFIX "sampleRate", (int32_t)mSampleRate);
int32_t sample_rate = -1;
@@ -123,9 +123,9 @@
metrics_proto.set_channel_mask(channel_mask);
}
// item->setCString(MM_PREFIX "encoding", toString(mFormat).c_str());
- char *encoding = NULL;
- if (item->getCString(MM_PREFIX "encoding", &encoding)) {
- metrics_proto.set_encoding(encoding);
+ std::string encoding;
+ if (item->getString(MM_PREFIX "encoding", &encoding)) {
+ metrics_proto.set_encoding(std::move(encoding));
}
// item->setInt32(MM_PREFIX "frameCount", (int32_t)mFrameCount);
int32_t frame_count = -1;
@@ -133,14 +133,14 @@
metrics_proto.set_frame_count(frame_count);
}
// item->setCString(MM_PREFIX "outDevice", toString(mOutDevice).c_str());
- char *outDevice = NULL;
- if (item->getCString(MM_PREFIX "outDevice", &outDevice)) {
- metrics_proto.set_output_device(outDevice);
+ std::string outDevice;
+ if (item->getString(MM_PREFIX "outDevice", &outDevice)) {
+ metrics_proto.set_output_device(std::move(outDevice));
}
// item->setCString(MM_PREFIX "inDevice", toString(mInDevice).c_str());
- char *inDevice = NULL;
- if (item->getCString(MM_PREFIX "inDevice", &inDevice)) {
- metrics_proto.set_input_device(inDevice);
+ std::string inDevice;
+ if (item->getString(MM_PREFIX "inDevice", &inDevice)) {
+ metrics_proto.set_input_device(std::move(inDevice));
}
// item->setDouble(MM_PREFIX "ioJitterMs.mean", mIoJitterMs.getMean());
double iojitters_ms_mean = -1;
@@ -201,16 +201,6 @@
ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
}
- // must free the strings that we were given
- free(mytype);
- free(workhist);
- free(latencyhist);
- free(warmuphist);
- free(type);
- free(encoding);
- free(inDevice);
- free(outDevice);
-
return true;
}
diff --git a/services/mediaanalytics/statsd_audiotrack.cpp b/services/mediaanalytics/statsd_audiotrack.cpp
index f250ced..57cda99 100644
--- a/services/mediaanalytics/statsd_audiotrack.cpp
+++ b/services/mediaanalytics/statsd_audiotrack.cpp
@@ -57,23 +57,23 @@
// static constexpr char kAudioTrackStreamType[] = "android.media.audiotrack.streamtype";
// optional string streamType;
- char *streamtype = NULL;
- if (item->getCString("android.media.audiotrack.streamtype", &streamtype)) {
- metrics_proto.set_stream_type(streamtype);
+ std::string streamtype;
+ if (item->getString("android.media.audiotrack.streamtype", &streamtype)) {
+ metrics_proto.set_stream_type(std::move(streamtype));
}
// static constexpr char kAudioTrackContentType[] = "android.media.audiotrack.type";
// optional string contentType;
- char *contenttype = NULL;
- if (item->getCString("android.media.audiotrack.type", &contenttype)) {
- metrics_proto.set_content_type(contenttype);
+ std::string contenttype;
+ if (item->getString("android.media.audiotrack.type", &contenttype)) {
+ metrics_proto.set_content_type(std::move(contenttype));
}
// static constexpr char kAudioTrackUsage[] = "android.media.audiotrack.usage";
// optional string trackUsage;
- char *trackusage = NULL;
- if (item->getCString("android.media.audiotrack.usage", &trackusage)) {
- metrics_proto.set_track_usage(trackusage);
+ std::string trackusage;
+ if (item->getString("android.media.audiotrack.usage", &trackusage)) {
+ metrics_proto.set_track_usage(std::move(trackusage));
}
// static constexpr char kAudioTrackSampleRate[] = "android.media.audiotrack.samplerate";
@@ -111,9 +111,9 @@
metrics_proto.set_port_id(port_id);
}
// encoding (string)
- char *encoding = NULL;
- if (item->getCString("android.media.audiotrack.encoding", &encoding)) {
- metrics_proto.set_encoding(encoding);
+ std::string encoding;
+ if (item->getString("android.media.audiotrack.encoding", &encoding)) {
+ metrics_proto.set_encoding(std::move(encoding));
}
// frameCount (int32)
int32_t frame_count = -1;
@@ -121,9 +121,9 @@
metrics_proto.set_frame_count(frame_count);
}
// attributes (string)
- char *attributes = NULL;
- if (item->getCString("android.media.audiotrack.attributes", &attributes)) {
- metrics_proto.set_attributes(attributes);
+ std::string attributes;
+ if (item->getString("android.media.audiotrack.attributes", &attributes)) {
+ metrics_proto.set_attributes(std::move(attributes));
}
std::string serialized;
@@ -143,13 +143,6 @@
ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
}
- // must free the strings that we were given
- free(streamtype);
- free(contenttype);
- free(trackusage);
- free(encoding);
- free(attributes);
-
return true;
}
diff --git a/services/mediaanalytics/statsd_codec.cpp b/services/mediaanalytics/statsd_codec.cpp
index dc8e4ef..bf82e50 100644
--- a/services/mediaanalytics/statsd_codec.cpp
+++ b/services/mediaanalytics/statsd_codec.cpp
@@ -55,19 +55,19 @@
// flesh out the protobuf we'll hand off with our data
//
// android.media.mediacodec.codec string
- char *codec = NULL;
- if (item->getCString("android.media.mediacodec.codec", &codec)) {
- metrics_proto.set_codec(codec);
+ std::string codec;
+ if (item->getString("android.media.mediacodec.codec", &codec)) {
+ metrics_proto.set_codec(std::move(codec));
}
// android.media.mediacodec.mime string
- char *mime = NULL;
- if (item->getCString("android.media.mediacodec.mime", &mime)) {
- metrics_proto.set_mime(mime);
+ std::string mime;
+ if (item->getString("android.media.mediacodec.mime", &mime)) {
+ metrics_proto.set_mime(std::move(mime));
}
// android.media.mediacodec.mode string
- char *mode = NULL;
- if ( item->getCString("android.media.mediacodec.mode", &mode)) {
- metrics_proto.set_mode(mode);
+ std::string mode;
+ if ( item->getString("android.media.mediacodec.mode", &mode)) {
+ metrics_proto.set_mode(std::move(mode));
}
// android.media.mediacodec.encoder int32
int32_t encoder = -1;
@@ -125,9 +125,9 @@
metrics_proto.set_error_code(errcode);
}
// android.media.mediacodec.errstate string
- char *errstate = NULL;
- if ( item->getCString("android.media.mediacodec.errstate", &errstate)) {
- metrics_proto.set_error_state(errstate);
+ std::string errstate;
+ if ( item->getString("android.media.mediacodec.errstate", &errstate)) {
+ metrics_proto.set_error_state(std::move(errstate));
}
// android.media.mediacodec.latency.max int64
int64_t latency_max = -1;
@@ -173,12 +173,6 @@
ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
}
- // must free the strings that we were given
- free(codec);
- free(mime);
- free(mode);
- free(errstate);
-
return true;
}
diff --git a/services/mediaanalytics/statsd_extractor.cpp b/services/mediaanalytics/statsd_extractor.cpp
index 395c912..d84930c 100644
--- a/services/mediaanalytics/statsd_extractor.cpp
+++ b/services/mediaanalytics/statsd_extractor.cpp
@@ -56,14 +56,14 @@
//
// android.media.mediaextractor.fmt string
- char *fmt = NULL;
- if (item->getCString("android.media.mediaextractor.fmt", &fmt)) {
- metrics_proto.set_format(fmt);
+ std::string fmt;
+ if (item->getString("android.media.mediaextractor.fmt", &fmt)) {
+ metrics_proto.set_format(std::move(fmt));
}
// android.media.mediaextractor.mime string
- char *mime = NULL;
- if (item->getCString("android.media.mediaextractor.mime", &mime)) {
- metrics_proto.set_mime(mime);
+ std::string mime;
+ if (item->getString("android.media.mediaextractor.mime", &mime)) {
+ metrics_proto.set_mime(std::move(mime));
}
// android.media.mediaextractor.ntrk int32
int32_t ntrk = -1;
@@ -88,10 +88,6 @@
ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
}
- // must free the strings that we were given
- free(fmt);
- free(mime);
-
return true;
}
diff --git a/services/mediaanalytics/statsd_nuplayer.cpp b/services/mediaanalytics/statsd_nuplayer.cpp
index 5ec118a..e6e0f2c 100644
--- a/services/mediaanalytics/statsd_nuplayer.cpp
+++ b/services/mediaanalytics/statsd_nuplayer.cpp
@@ -62,13 +62,13 @@
// differentiate between nuplayer and nuplayer2
metrics_proto.set_whichplayer(item->getKey().c_str());
- char *video_mime = NULL;
- if (item->getCString("android.media.mediaplayer.video.mime", &video_mime)) {
- metrics_proto.set_video_mime(video_mime);
+ std::string video_mime;
+ if (item->getString("android.media.mediaplayer.video.mime", &video_mime)) {
+ metrics_proto.set_video_mime(std::move(video_mime));
}
- char *video_codec = NULL;
- if (item->getCString("android.media.mediaplayer.video.codec", &video_codec)) {
- metrics_proto.set_video_codec(video_codec);
+ std::string video_codec;
+ if (item->getString("android.media.mediaplayer.video.codec", &video_codec)) {
+ metrics_proto.set_video_codec(std::move(video_codec));
}
int32_t width = -1;
@@ -97,13 +97,13 @@
metrics_proto.set_framerate(fps);
}
- char *audio_mime = NULL;
- if (item->getCString("android.media.mediaplayer.audio.mime", &audio_mime)) {
- metrics_proto.set_audio_mime(audio_mime);
+ std::string audio_mime;
+ if (item->getString("android.media.mediaplayer.audio.mime", &audio_mime)) {
+ metrics_proto.set_audio_mime(std::move(audio_mime));
}
- char *audio_codec = NULL;
- if (item->getCString("android.media.mediaplayer.audio.codec", &audio_codec)) {
- metrics_proto.set_audio_codec(audio_codec);
+ std::string audio_codec;
+ if (item->getString("android.media.mediaplayer.audio.codec", &audio_codec)) {
+ metrics_proto.set_audio_codec(std::move(audio_codec));
}
int64_t duration_ms = -1;
@@ -123,14 +123,14 @@
if (item->getInt32("android.media.mediaplayer.errcode", &error_code)) {
metrics_proto.set_error_code(error_code);
}
- char *error_state = NULL;
- if (item->getCString("android.media.mediaplayer.errstate", &error_state)) {
- metrics_proto.set_error_state(error_state);
+ std::string error_state;
+ if (item->getString("android.media.mediaplayer.errstate", &error_state)) {
+ metrics_proto.set_error_state(std::move(error_state));
}
- char *data_source_type = NULL;
- if (item->getCString("android.media.mediaplayer.dataSource", &data_source_type)) {
- metrics_proto.set_data_source_type(data_source_type);
+ std::string data_source_type;
+ if (item->getString("android.media.mediaplayer.dataSource", &data_source_type)) {
+ metrics_proto.set_data_source_type(std::move(data_source_type));
}
int64_t rebufferingMs = -1;
@@ -164,14 +164,6 @@
ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
}
- // must free the strings that we were given
- free(video_mime);
- free(video_codec);
- free(audio_mime);
- free(audio_codec);
- free(error_state);
- free(data_source_type);
-
return true;
}
diff --git a/services/mediaanalytics/statsd_recorder.cpp b/services/mediaanalytics/statsd_recorder.cpp
index 4d981b4..d286f00 100644
--- a/services/mediaanalytics/statsd_recorder.cpp
+++ b/services/mediaanalytics/statsd_recorder.cpp
@@ -56,14 +56,14 @@
//
// string kRecorderAudioMime = "android.media.mediarecorder.audio.mime";
- char *audio_mime = NULL;
- if (item->getCString("android.media.mediarecorder.audio.mime", &audio_mime)) {
- metrics_proto.set_audio_mime(audio_mime);
+ std::string audio_mime;
+ if (item->getString("android.media.mediarecorder.audio.mime", &audio_mime)) {
+ metrics_proto.set_audio_mime(std::move(audio_mime));
}
// string kRecorderVideoMime = "android.media.mediarecorder.video.mime";
- char *video_mime = NULL;
- if (item->getCString("android.media.mediarecorder.video.mime", &video_mime)) {
- metrics_proto.set_video_mime(video_mime);
+ std::string video_mime;
+ if (item->getString("android.media.mediarecorder.video.mime", &video_mime)) {
+ metrics_proto.set_video_mime(std::move(video_mime));
}
// int32 kRecorderVideoProfile = "android.media.mediarecorder.video-encoder-profile";
int32_t videoProfile = -1;
@@ -183,10 +183,6 @@
ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
}
- // must free the strings that we were given
- free(audio_mime);
- free(video_mime);
-
return true;
}