Merge "audio policy: fix regression with duplicated output handle"
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index d35a52b..a81fe8c 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -6998,19 +6998,24 @@
* <li>ACAMERA_LENS_RADIAL_DISTORTION</li>
* </ul>
* </li>
+ * <li>The SENSOR_INFO_TIMESTAMP_SOURCE of the logical device and physical devices must be
+ * the same.</li>
* <li>The logical camera device must be LIMITED or higher device.</li>
* </ul>
* <p>Both the logical camera device and its underlying physical devices support the
* mandatory stream combinations required for their device levels.</p>
* <p>Additionally, for each guaranteed stream combination, the logical camera supports:</p>
* <ul>
- * <li>Replacing one logical {@link AIMAGE_FORMAT_YUV_420_888 YUV_420_888}
+ * <li>For each guaranteed stream combination, the logical camera supports replacing one
+ * logical {@link AIMAGE_FORMAT_YUV_420_888 YUV_420_888}
* or raw stream with two physical streams of the same size and format, each from a
* separate physical camera, given that the size and format are supported by both
* physical cameras.</li>
- * <li>Adding two raw streams, each from one physical camera, if the logical camera doesn't
- * advertise RAW capability, but the underlying physical cameras do. This is usually
- * the case when the physical cameras have different sensor sizes.</li>
+ * <li>If the logical camera doesn't advertise RAW capability, but the underlying physical
+ * cameras do, the logical camera will support guaranteed stream combinations for RAW
+ * capability, except that the RAW streams will be physical streams, each from a separate
+ * physical camera. This is usually the case when the physical cameras have different
+ * sensor sizes.</li>
* </ul>
* <p>Using physical streams in place of a logical stream of the same size and format will
* not slow down the frame rate of the capture, as long as the minimum frame duration
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index 46bd8f0..9d2daab 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -50,6 +50,7 @@
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaMuxer.h>
+#include <media/stagefright/PersistentSurface.h>
#include <media/ICrypto.h>
#include <media/MediaCodecBuffer.h>
@@ -70,6 +71,7 @@
static bool gVerbose = false; // chatty on stdout
static bool gRotate = false; // rotate 90 degrees
static bool gMonotonicTime = false; // use system monotonic time for timestamps
+static bool gPersistentSurface = false; // use persistent surface
static enum {
FORMAT_MP4, FORMAT_H264, FORMAT_FRAMES, FORMAT_RAW_FRAMES
} gOutputFormat = FORMAT_MP4; // data format for output
@@ -199,10 +201,18 @@
ALOGV("Creating encoder input surface");
sp<IGraphicBufferProducer> bufferProducer;
- err = codec->createInputSurface(&bufferProducer);
+ if (gPersistentSurface) {
+ sp<PersistentSurface> surface = MediaCodec::CreatePersistentInputSurface();
+ bufferProducer = surface->getBufferProducer();
+ err = codec->setInputSurface(surface);
+ } else {
+ err = codec->createInputSurface(&bufferProducer);
+ }
if (err != NO_ERROR) {
fprintf(stderr,
- "ERROR: unable to create encoder input surface (err=%d)\n", err);
+ "ERROR: unable to %s encoder input surface (err=%d)\n",
+ gPersistentSurface ? "set" : "create",
+ err);
codec->release();
return err;
}
@@ -920,6 +930,7 @@
{ "output-format", required_argument, NULL, 'o' },
{ "codec-name", required_argument, NULL, 'N' },
{ "monotonic-time", no_argument, NULL, 'm' },
+ { "persistent-surface", no_argument, NULL, 'p' },
{ NULL, 0, NULL, 0 }
};
@@ -1005,6 +1016,9 @@
case 'm':
gMonotonicTime = true;
break;
+ case 'p':
+ gPersistentSurface = true;
+ break;
default:
if (ic != '?') {
fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic);
diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp
index cad8caf..9e40a0f 100644
--- a/cmds/stagefright/SineSource.cpp
+++ b/cmds/stagefright/SineSource.cpp
@@ -4,6 +4,7 @@
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
@@ -59,10 +60,10 @@
}
status_t SineSource::read(
- MediaBuffer **out, const ReadOptions * /* options */) {
+ MediaBufferBase **out, const ReadOptions * /* options */) {
*out = NULL;
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
status_t err = mGroup->acquire_buffer(&buffer);
if (err != OK) {
diff --git a/cmds/stagefright/SineSource.h b/cmds/stagefright/SineSource.h
index f1fb96d..1817291 100644
--- a/cmds/stagefright/SineSource.h
+++ b/cmds/stagefright/SineSource.h
@@ -18,7 +18,7 @@
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **out, const ReadOptions *options = NULL);
+ MediaBufferBase **out, const ReadOptions *options = NULL);
protected:
virtual ~SineSource();
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index fc24646..d4f2e8d 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -169,7 +169,7 @@
ALOGI("Line: %d", __LINE__);
} else {
CHECK_EQ(decoder->start(), (status_t)OK);
- MediaBuffer* buffer;
+ MediaBufferBase* buffer;
while (decoder->read(&buffer) == OK) {
// do something with buffer (save it eventually?)
// need to stop after some count though...
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 073ee6b..44b0015 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -328,7 +328,7 @@
int32_t n = 0;
status_t err;
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
while ((err = encoder->read(&buffer)) == OK) {
printf(".");
fflush(stdout);
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index af39d46..b7a5066 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -90,7 +90,7 @@
}
virtual status_t read(
- MediaBuffer **buffer, const MediaSource::ReadOptions *options __unused) {
+ MediaBufferBase **buffer, const MediaSource::ReadOptions *options __unused) {
if (mNumFramesOutput % 10 == 0) {
fprintf(stderr, ".");
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index bb517aa..5fa8304 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -150,7 +150,7 @@
status_t err;
for (;;) {
- MediaBuffer *mbuf;
+ MediaBufferBase *mbuf;
err = source->read(&mbuf);
if (err == INFO_FORMAT_CHANGED) {
@@ -234,7 +234,7 @@
CHECK(meta->findInt64(kKeyDuration, &durationUs));
status_t err;
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
MediaSource::ReadOptions options;
int64_t seekTimeUs = -1;
for (;;) {
@@ -321,7 +321,7 @@
while (numIterationsLeft-- > 0) {
long numFrames = 0;
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
for (;;) {
int64_t startDecodeUs = getNowUs();
@@ -416,7 +416,7 @@
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options);
+ MediaBufferBase **buffer, const ReadOptions *options);
private:
enum StreamType {
@@ -465,7 +465,7 @@
return mSource->getFormat();
}
-static bool isIDRFrame(MediaBuffer *buffer) {
+static bool isIDRFrame(MediaBufferBase *buffer) {
const uint8_t *data =
(const uint8_t *)buffer->data() + buffer->range_offset();
size_t size = buffer->range_length();
@@ -482,7 +482,7 @@
}
status_t DetectSyncSource::read(
- MediaBuffer **buffer, const ReadOptions *options) {
+ MediaBufferBase **buffer, const ReadOptions *options) {
for (;;) {
status_t err = mSource->read(buffer, options);
@@ -562,7 +562,7 @@
options.setSeekTo(
seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
status_t err;
for (;;) {
err = source->read(&buffer, &options);
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index ea239c5..5ea4614 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -15,25 +15,20 @@
"IDrm.cpp",
"IDrmClient.cpp",
"IMediaDrmService.cpp",
- "PluginMetricsReporting.cpp",
"SharedLibrary.cpp",
"DrmHal.cpp",
- "DrmMetrics.cpp",
"CryptoHal.cpp",
- "protos/plugin_metrics.proto",
],
- proto: {
- type: "lite",
- },
-
shared_libs: [
"libbinder",
"libcutils",
"libdl",
"liblog",
+ "libmediadrmmetrics_lite",
"libmediametrics",
"libmediautils",
+ "libprotobuf-cpp-lite",
"libstagefright_foundation",
"libutils",
"android.hardware.drm@1.0",
@@ -48,3 +43,66 @@
"-Wall",
],
}
+
+// This is the version of the drm metrics configured for protobuf lite.
+cc_library_shared {
+ name: "libmediadrmmetrics_lite",
+ srcs: [
+ "DrmMetrics.cpp",
+ "PluginMetricsReporting.cpp",
+ "protos/metrics.proto",
+ ],
+
+ proto: {
+ export_proto_headers: true,
+ type: "lite",
+ },
+ shared_libs: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libmediametrics",
+ "libprotobuf-cpp-lite",
+ "libutils",
+ ],
+ cflags: [
+ // Suppress unused parameter and no error options. These cause problems
+ // with the when using the map type in a proto definition.
+ "-Wno-unused-parameter",
+ "-Wno-error",
+ ],
+}
+
+// This is the version of the drm metrics library configured for full protobuf.
+cc_library_shared {
+ name: "libmediadrmmetrics_full",
+ srcs: [
+ "DrmMetrics.cpp",
+ "PluginMetricsReporting.cpp",
+ "protos/metrics.proto",
+ ],
+
+ proto: {
+ export_proto_headers: true,
+ type: "full",
+ },
+ shared_libs: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libmediametrics",
+ "libprotobuf-cpp-full",
+ "libutils",
+ ],
+ cflags: [
+ // Suppress unused parameter and no error options. These cause problems
+ // when using the map type in a proto definition.
+ "-Wno-unused-parameter",
+ "-Wno-error",
+ ],
+}
+
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 039e1e9..48f4479 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -16,6 +16,8 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "DrmHal"
+#include <iomanip>
+
#include <utils/Log.h>
#include <binder/IPCThreadState.h>
@@ -52,6 +54,7 @@
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hidl::manager::V1_0::IServiceManager;
+using ::android::os::PersistableBundle;
using ::android::sp;
namespace {
@@ -97,6 +100,15 @@
return hidl_string(string.string());
}
+std::string ToHexString(const std::string& str) {
+ std::ostringstream out;
+ out << std::hex << std::setfill('0');
+ for (size_t i = 0; i < str.size(); i++) {
+ out << std::setw(2) << (int)(str[i]);
+ }
+ return out.str();
+}
+
static DrmPlugin::SecurityLevel toSecurityLevel(SecurityLevel level) {
switch(level) {
case SecurityLevel::SW_SECURE_CRYPTO:
@@ -308,6 +320,7 @@
sp<IDrmPlugin> DrmHal::makeDrmPlugin(const sp<IDrmFactory>& factory,
const uint8_t uuid[16], const String8& appPackageName) {
+ mMetrics.SetAppPackageName(appPackageName);
sp<IDrmPlugin> plugin;
Return<void> hResult = factory->createPlugin(uuid, appPackageName.string(),
@@ -503,7 +516,8 @@
INIT_CHECK();
closeOpenSessions();
- reportMetrics();
+ reportPluginMetrics();
+ reportFrameworkMetrics();
setListener(NULL);
mInitCheck = NO_INIT;
@@ -594,6 +608,7 @@
DrmSessionManager::Instance()->addSession(getCallingPid(),
mDrmSessionClient, sessionId);
mOpenSessions.push(sessionId);
+ mMetrics.SetSessionStart(sessionId);
}
mMetrics.mOpenSessionCounter.Increment(err);
@@ -615,9 +630,10 @@
}
}
}
- reportMetrics();
status_t response = toStatusT(status);
+ mMetrics.SetSessionEnd(sessionId);
mMetrics.mCloseSessionCounter.Increment(response);
+ reportPluginMetrics();
return response;
}
mMetrics.mCloseSessionCounter.Increment(DEAD_OBJECT);
@@ -631,7 +647,7 @@
String8 &defaultUrl, DrmPlugin::KeyRequestType *keyRequestType) {
Mutex::Autolock autoLock(mLock);
INIT_CHECK();
- EventTimer<status_t> keyRequestTimer(&mMetrics.mGetKeyRequestTiming);
+ EventTimer<status_t> keyRequestTimer(&mMetrics.mGetKeyRequestTimeUs);
DrmSessionManager::Instance()->useSession(sessionId);
@@ -726,7 +742,7 @@
status_t DrmHal::provideKeyResponse(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &response, Vector<uint8_t> &keySetId) {
Mutex::Autolock autoLock(mLock);
- EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTiming);
+ EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
INIT_CHECK();
@@ -1095,7 +1111,7 @@
return toStatusT(status);
}
-status_t DrmHal::getMetrics(MediaAnalyticsItem* item) {
+status_t DrmHal::getMetrics(PersistableBundle* item) {
if (item == nullptr) {
return UNEXPECTED_NULL;
}
@@ -1274,8 +1290,41 @@
}
}
+void DrmHal::reportFrameworkMetrics() const
+{
+ MediaAnalyticsItem item("mediadrm");
+ item.generateSessionID();
+ item.setPkgName(mMetrics.GetAppPackageName().c_str());
+ String8 vendor;
+ String8 description;
+ status_t result = getPropertyStringInternal(String8("vendor"), vendor);
+ if (result != OK) {
+ ALOGE("Failed to get vendor from drm plugin. %d", result);
+ } else {
+ item.setCString("vendor", vendor.c_str());
+ }
+ result = getPropertyStringInternal(String8("description"), description);
+ if (result != OK) {
+ ALOGE("Failed to get description from drm plugin. %d", result);
+ } else {
+ item.setCString("description", description.c_str());
+ }
-void DrmHal::reportMetrics() const
+ std::string serializedMetrics;
+ result = mMetrics.GetSerializedMetrics(&serializedMetrics);
+ if (result != OK) {
+ ALOGE("Failed to serialize Framework metrics: %d", result);
+ }
+ serializedMetrics = ToHexString(serializedMetrics);
+ if (!serializedMetrics.empty()) {
+ item.setCString("serialized_metrics", serializedMetrics.c_str());
+ }
+ if (!item.selfrecord()) {
+ ALOGE("Failed to self record framework metrics.");
+ }
+}
+
+void DrmHal::reportPluginMetrics() const
{
Vector<uint8_t> metrics;
String8 vendor;
diff --git a/drm/libmediadrm/DrmMetrics.cpp b/drm/libmediadrm/DrmMetrics.cpp
index 258c4b0..03bd88a 100644
--- a/drm/libmediadrm/DrmMetrics.cpp
+++ b/drm/libmediadrm/DrmMetrics.cpp
@@ -13,140 +13,330 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define LOG_TAG "DrmMetrics"
+#include <iomanip>
+#include <utility>
#include <android-base/macros.h>
#include <media/DrmMetrics.h>
+#include <media/stagefright/foundation/base64.h>
+#include <sys/time.h>
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include "protos/metrics.pb.h"
+
+using ::android::String16;
+using ::android::String8;
+using ::android::drm_metrics::DrmFrameworkMetrics;
using ::android::hardware::drm::V1_0::EventType;
using ::android::hardware::drm::V1_0::KeyStatusType;
+using ::android::os::PersistableBundle;
namespace {
-template<typename T>
-std::string GetAttributeName(T type);
+template <typename T> std::string GetAttributeName(T type);
-template<>
-std::string GetAttributeName<KeyStatusType>(KeyStatusType type) {
- static const char* type_names[] = {
- "USABLE", "EXPIRED", "OUTPUT_NOT_ALLOWED",
- "STATUS_PENDING", "INTERNAL_ERROR" };
- if (((size_t) type) > arraysize(type_names)) {
- return "UNKNOWN_TYPE";
- }
- return type_names[(size_t) type];
+template <> std::string GetAttributeName<KeyStatusType>(KeyStatusType type) {
+ static const char *type_names[] = {"USABLE", "EXPIRED",
+ "OUTPUT_NOT_ALLOWED", "STATUS_PENDING",
+ "INTERNAL_ERROR"};
+ if (((size_t)type) > arraysize(type_names)) {
+ return "UNKNOWN_TYPE";
+ }
+ return type_names[(size_t)type];
}
-template<>
-std::string GetAttributeName<EventType>(EventType type) {
- static const char* type_names[] = {
- "PROVISION_REQUIRED", "KEY_NEEDED", "KEY_EXPIRED",
- "VENDOR_DEFINED", "SESSION_RECLAIMED" };
- if (((size_t) type) > arraysize(type_names)) {
- return "UNKNOWN_TYPE";
- }
- return type_names[(size_t) type];
+template <> std::string GetAttributeName<EventType>(EventType type) {
+ static const char *type_names[] = {"PROVISION_REQUIRED", "KEY_NEEDED",
+ "KEY_EXPIRED", "VENDOR_DEFINED",
+ "SESSION_RECLAIMED"};
+ if (((size_t)type) > arraysize(type_names)) {
+ return "UNKNOWN_TYPE";
+ }
+ return type_names[(size_t)type];
}
-template<typename T>
-void ExportCounterMetric(const android::CounterMetric<T>& counter,
- android::MediaAnalyticsItem* item) {
- if (!item) {
- ALOGE("item was unexpectedly null.");
- return;
- }
- std::string success_count_name = counter.metric_name() + ".ok.count";
- std::string error_count_name = counter.metric_name() + ".error.count";
- counter.ExportValues(
- [&] (const android::status_t status, const int64_t value) {
- if (status == android::OK) {
- item->setInt64(success_count_name.c_str(), value);
- } else {
- int64_t total_errors(0);
- item->getInt64(error_count_name.c_str(), &total_errors);
- item->setInt64(error_count_name.c_str(), total_errors + value);
- // TODO: Add support for exporting the list of error values.
- // This probably needs to be added to MediaAnalyticsItem.
- }
- });
+template <typename T>
+void ExportCounterMetric(const android::CounterMetric<T> &counter,
+ PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+ std::string success_count_name = counter.metric_name() + ".ok.count";
+ std::string error_count_name = counter.metric_name() + ".error.count";
+ std::vector<int64_t> status_values;
+ counter.ExportValues(
+ [&](const android::status_t status, const int64_t value) {
+ if (status == android::OK) {
+ metrics->putLong(android::String16(success_count_name.c_str()),
+ value);
+ } else {
+ int64_t total_errors(0);
+ metrics->getLong(android::String16(error_count_name.c_str()),
+ &total_errors);
+ metrics->putLong(android::String16(error_count_name.c_str()),
+ total_errors + value);
+ status_values.push_back(status);
+ }
+ });
+ if (!status_values.empty()) {
+ std::string error_list_name = counter.metric_name() + ".error.list";
+ metrics->putLongVector(android::String16(error_list_name.c_str()),
+ status_values);
+ }
}
-template<typename T>
+template <typename T>
void ExportCounterMetricWithAttributeNames(
- const android::CounterMetric<T>& counter,
- android::MediaAnalyticsItem* item) {
- if (!item) {
- ALOGE("item was unexpectedly null.");
- return;
- }
- counter.ExportValues(
- [&] (const T& attribute, const int64_t value) {
- std::string name = counter.metric_name()
- + "." + GetAttributeName(attribute) + ".count";
- item->setInt64(name.c_str(), value);
- });
+ const android::CounterMetric<T> &counter, PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+ counter.ExportValues([&](const T &attribute, const int64_t value) {
+ std::string name = counter.metric_name() + "." +
+ GetAttributeName(attribute) + ".count";
+ metrics->putLong(android::String16(name.c_str()), value);
+ });
}
-template<typename T>
-void ExportEventMetric(const android::EventMetric<T>& event,
- android::MediaAnalyticsItem* item) {
- if (!item) {
- ALOGE("item was unexpectedly null.");
- return;
- }
- std::string success_count_name = event.metric_name() + ".ok.count";
- std::string error_count_name = event.metric_name() + ".error.count";
- std::string timing_name = event.metric_name() + ".ok.average_time_micros";
- event.ExportValues(
- [&] (const android::status_t& status,
- const android::EventStatistics& value) {
- if (status == android::OK) {
- item->setInt64(success_count_name.c_str(), value.count);
- item->setInt64(timing_name.c_str(), value.mean);
- } else {
- int64_t total_errors(0);
- item->getInt64(error_count_name.c_str(), &total_errors);
- item->setInt64(error_count_name.c_str(),
+template <typename T>
+void ExportEventMetric(const android::EventMetric<T> &event,
+ PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+ std::string success_count_name = event.metric_name() + ".ok.count";
+ std::string error_count_name = event.metric_name() + ".error.count";
+ std::string timing_name = event.metric_name() + ".ok.average_time_micros";
+ std::vector<int64_t> status_values;
+ event.ExportValues([&](const android::status_t &status,
+ const android::EventStatistics &value) {
+ if (status == android::OK) {
+ metrics->putLong(android::String16(success_count_name.c_str()),
+ value.count);
+ metrics->putLong(android::String16(timing_name.c_str()),
+ value.mean);
+ } else {
+ int64_t total_errors(0);
+ metrics->getLong(android::String16(error_count_name.c_str()),
+ &total_errors);
+ metrics->putLong(android::String16(error_count_name.c_str()),
total_errors + value.count);
- // TODO: Add support for exporting the list of error values.
- // This probably needs to be added to MediaAnalyticsItem.
- }
- });
+ status_values.push_back(status);
+ }
+ });
+ if (!status_values.empty()) {
+ std::string error_list_name = event.metric_name() + ".error.list";
+ metrics->putLongVector(android::String16(error_list_name.c_str()),
+ status_values);
+ }
}
-} // namespace anonymous
+void ExportSessionLifespans(
+ const std::map<std::string, std::pair<int64_t, int64_t>> &mSessionLifespans,
+ PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+
+ if (mSessionLifespans.empty()) {
+ return;
+ }
+
+ PersistableBundle startTimesBundle;
+ PersistableBundle endTimesBundle;
+ for (auto it = mSessionLifespans.begin(); it != mSessionLifespans.end();
+ it++) {
+ String16 key(it->first.c_str(), it->first.size());
+ startTimesBundle.putLong(key, it->second.first);
+ endTimesBundle.putLong(key, it->second.second);
+ }
+ metrics->putPersistableBundle(
+ android::String16("drm.mediadrm.session_start_times_ms"),
+ startTimesBundle);
+ metrics->putPersistableBundle(
+ android::String16("drm.mediadrm.session_end_times_ms"), endTimesBundle);
+}
+
+std::string ToHexString(const android::Vector<uint8_t> &sessionId) {
+ std::ostringstream out;
+ out << std::hex << std::setfill('0');
+ for (size_t i = 0; i < sessionId.size(); i++) {
+ out << std::setw(2) << (int)(sessionId[i]);
+ }
+ return out.str();
+}
+
+} // namespace
namespace android {
MediaDrmMetrics::MediaDrmMetrics()
: mOpenSessionCounter("drm.mediadrm.open_session", "status"),
mCloseSessionCounter("drm.mediadrm.close_session", "status"),
- mGetKeyRequestTiming("drm.mediadrm.get_key_request", "status"),
- mProvideKeyResponseTiming("drm.mediadrm.provide_key_response", "status"),
- mGetProvisionRequestCounter(
- "drm.mediadrm.get_provision_request", "status"),
+ mGetKeyRequestTimeUs("drm.mediadrm.get_key_request", "status"),
+ mProvideKeyResponseTimeUs("drm.mediadrm.provide_key_response", "status"),
+ mGetProvisionRequestCounter("drm.mediadrm.get_provision_request",
+ "status"),
mProvideProvisionResponseCounter(
"drm.mediadrm.provide_provision_response", "status"),
- mKeyStatusChangeCounter(
- "drm.mediadrm.key_status_change", "key_status_type"),
+ mKeyStatusChangeCounter("drm.mediadrm.key_status_change",
+ "key_status_type"),
mEventCounter("drm.mediadrm.event", "event_type"),
- mGetDeviceUniqueIdCounter(
- "drm.mediadrm.get_device_unique_id", "status") {
+ mGetDeviceUniqueIdCounter("drm.mediadrm.get_device_unique_id", "status") {
}
-void MediaDrmMetrics::Export(MediaAnalyticsItem* item) {
- if (!item) {
- ALOGE("item was unexpectedly null.");
- return;
- }
- ExportCounterMetric(mOpenSessionCounter, item);
- ExportCounterMetric(mCloseSessionCounter, item);
- ExportEventMetric(mGetKeyRequestTiming, item);
- ExportEventMetric(mProvideKeyResponseTiming, item);
- ExportCounterMetric(mGetProvisionRequestCounter, item);
- ExportCounterMetric(mProvideProvisionResponseCounter, item);
- ExportCounterMetricWithAttributeNames(mKeyStatusChangeCounter, item);
- ExportCounterMetricWithAttributeNames(mEventCounter, item);
- ExportCounterMetric(mGetDeviceUniqueIdCounter, item);
+void MediaDrmMetrics::SetSessionStart(
+ const android::Vector<uint8_t> &sessionId) {
+ std::string sessionIdHex = ToHexString(sessionId);
+ mSessionLifespans[sessionIdHex] =
+ std::make_pair(GetCurrentTimeMs(), (int64_t)0);
}
-} // namespace android
+void MediaDrmMetrics::SetSessionEnd(const android::Vector<uint8_t> &sessionId) {
+ std::string sessionIdHex = ToHexString(sessionId);
+ int64_t endTimeMs = GetCurrentTimeMs();
+ if (mSessionLifespans.find(sessionIdHex) != mSessionLifespans.end()) {
+ mSessionLifespans[sessionIdHex] =
+ std::make_pair(mSessionLifespans[sessionIdHex].first, endTimeMs);
+ } else {
+ mSessionLifespans[sessionIdHex] = std::make_pair((int64_t)0, endTimeMs);
+ }
+}
+
+void MediaDrmMetrics::Export(PersistableBundle *metrics) {
+ if (!metrics) {
+ ALOGE("metrics was unexpectedly null.");
+ return;
+ }
+ ExportCounterMetric(mOpenSessionCounter, metrics);
+ ExportCounterMetric(mCloseSessionCounter, metrics);
+ ExportEventMetric(mGetKeyRequestTimeUs, metrics);
+ ExportEventMetric(mProvideKeyResponseTimeUs, metrics);
+ ExportCounterMetric(mGetProvisionRequestCounter, metrics);
+ ExportCounterMetric(mProvideProvisionResponseCounter, metrics);
+ ExportCounterMetricWithAttributeNames(mKeyStatusChangeCounter, metrics);
+ ExportCounterMetricWithAttributeNames(mEventCounter, metrics);
+ ExportCounterMetric(mGetDeviceUniqueIdCounter, metrics);
+ ExportSessionLifespans(mSessionLifespans, metrics);
+}
+
+status_t MediaDrmMetrics::GetSerializedMetrics(std::string *serializedMetrics) {
+
+ if (!serializedMetrics) {
+ ALOGE("serializedMetrics was unexpectedly null.");
+ return UNEXPECTED_NULL;
+ }
+
+ DrmFrameworkMetrics metrics;
+
+ mOpenSessionCounter.ExportValues(
+ [&](const android::status_t status, const int64_t value) {
+ DrmFrameworkMetrics::Counter *counter =
+ metrics.add_open_session_counter();
+ counter->set_count(value);
+ counter->mutable_attributes()->set_error_code(status);
+ });
+
+ mCloseSessionCounter.ExportValues(
+ [&](const android::status_t status, const int64_t value) {
+ DrmFrameworkMetrics::Counter *counter =
+ metrics.add_close_session_counter();
+ counter->set_count(value);
+ counter->mutable_attributes()->set_error_code(status);
+ });
+
+ mGetProvisionRequestCounter.ExportValues(
+ [&](const android::status_t status, const int64_t value) {
+ DrmFrameworkMetrics::Counter *counter =
+ metrics.add_get_provisioning_request_counter();
+ counter->set_count(value);
+ counter->mutable_attributes()->set_error_code(status);
+ });
+
+ mProvideProvisionResponseCounter.ExportValues(
+ [&](const android::status_t status, const int64_t value) {
+ DrmFrameworkMetrics::Counter *counter =
+ metrics.add_provide_provisioning_response_counter();
+ counter->set_count(value);
+ counter->mutable_attributes()->set_error_code(status);
+ });
+
+ mKeyStatusChangeCounter.ExportValues(
+ [&](const KeyStatusType key_status_type, const int64_t value) {
+ DrmFrameworkMetrics::Counter *counter =
+ metrics.add_key_status_change_counter();
+ counter->set_count(value);
+ counter->mutable_attributes()->set_key_status_type(
+ (uint32_t)key_status_type);
+ });
+
+ mEventCounter.ExportValues(
+ [&](const EventType event_type, const int64_t value) {
+ DrmFrameworkMetrics::Counter *counter =
+ metrics.add_event_callback_counter();
+ counter->set_count(value);
+ counter->mutable_attributes()->set_event_type((uint32_t)event_type);
+ });
+
+ mGetDeviceUniqueIdCounter.ExportValues(
+ [&](const status_t status, const int64_t value) {
+ DrmFrameworkMetrics::Counter *counter =
+ metrics.add_get_device_unique_id_counter();
+ counter->set_count(value);
+ counter->mutable_attributes()->set_error_code(status);
+ });
+
+ mGetKeyRequestTimeUs.ExportValues(
+ [&](const status_t status, const EventStatistics &stats) {
+ DrmFrameworkMetrics::DistributionMetric *metric =
+ metrics.add_get_key_request_time_us();
+ metric->set_min(stats.min);
+ metric->set_max(stats.max);
+ metric->set_mean(stats.mean);
+ metric->set_operation_count(stats.count);
+ metric->set_variance(stats.sum_squared_deviation / stats.count);
+ metric->mutable_attributes()->set_error_code(status);
+ });
+
+ mProvideKeyResponseTimeUs.ExportValues(
+ [&](const status_t status, const EventStatistics &stats) {
+ DrmFrameworkMetrics::DistributionMetric *metric =
+ metrics.add_provide_key_response_time_us();
+ metric->set_min(stats.min);
+ metric->set_max(stats.max);
+ metric->set_mean(stats.mean);
+ metric->set_operation_count(stats.count);
+ metric->set_variance(stats.sum_squared_deviation / stats.count);
+ metric->mutable_attributes()->set_error_code(status);
+ });
+
+ for (const auto &sessionLifespan : mSessionLifespans) {
+ auto *map = metrics.mutable_session_lifetimes();
+
+ (*map)[sessionLifespan.first].set_start_time_ms(
+ sessionLifespan.second.first);
+ (*map)[sessionLifespan.first].set_end_time_ms(
+ sessionLifespan.second.second);
+ }
+
+ if (!metrics.SerializeToString(serializedMetrics)) {
+ ALOGE("Failed to serialize metrics.");
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+int64_t MediaDrmMetrics::GetCurrentTimeMs() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return ((int64_t)tv.tv_sec * 1000) + ((int64_t)tv.tv_usec / 1000);
+}
+
+} // namespace android
diff --git a/drm/libmediadrm/IDrm.cpp b/drm/libmediadrm/IDrm.cpp
index 9f54dba..22e4e6c 100644
--- a/drm/libmediadrm/IDrm.cpp
+++ b/drm/libmediadrm/IDrm.cpp
@@ -492,7 +492,10 @@
return reply.readInt32();
}
- virtual status_t getMetrics(MediaAnalyticsItem *item) {
+ virtual status_t getMetrics(os::PersistableBundle *metrics) {
+ if (metrics == NULL) {
+ return BAD_VALUE;
+ }
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
@@ -500,9 +503,23 @@
if (status != OK) {
return status;
}
+ // The reply data is ordered as
+ // 1) 32 bit integer reply followed by
+ // 2) Serialized PersistableBundle containing metrics.
+ status_t reply_status;
+ if (reply.readInt32(&reply_status) != OK
+ || reply_status != OK) {
+ ALOGE("Failed to read getMetrics response code from parcel. %d",
+ reply_status);
+ return reply_status;
+ }
- item->readFromParcel(reply);
- return reply.readInt32();
+ status = metrics->readFromParcel(&reply);
+ if (status != OK) {
+ ALOGE("Failed to read metrics from parcel. %d", status);
+ return status;
+ }
+ return reply_status;
}
virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
@@ -1008,11 +1025,18 @@
{
CHECK_INTERFACE(IDrm, data, reply);
- MediaAnalyticsItem item;
- status_t result = getMetrics(&item);
- item.writeToParcel(reply);
- reply->writeInt32(result);
- return OK;
+ os::PersistableBundle metrics;
+ status_t result = getMetrics(&metrics);
+ // The reply data is ordered as
+ // 1) 32 bit integer reply followed by
+ // 2) Serialized PersistableBundle containing metrics.
+ // Only write the metrics if the getMetrics result was
+ // OK and we successfully added the status to reply.
+ status_t parcel_result = reply->writeInt32(result);
+ if (result == OK && parcel_result == OK) {
+ parcel_result = metrics.writeToParcel(reply);
+ }
+ return parcel_result;
}
case SET_CIPHER_ALGORITHM:
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
index 26c8427..6c97f2b 100644
--- a/drm/libmediadrm/PluginMetricsReporting.cpp
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -23,7 +23,7 @@
#include <media/MediaAnalyticsItem.h>
-#include "protos/plugin_metrics.pb.h"
+#include "protos/metrics.pb.h"
namespace android {
diff --git a/drm/libmediadrm/protos/metrics.proto b/drm/libmediadrm/protos/metrics.proto
new file mode 100644
index 0000000..aa26f5f
--- /dev/null
+++ b/drm/libmediadrm/protos/metrics.proto
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package android.drm_metrics;
+
+// The MetricsGroup is a collection of metric name/value pair instances
+// that can be serialized and provided to a caller.
+message MetricsGroup {
+ message Metric {
+ message MetricValue {
+ // Exactly one of the following values must be set.
+ optional int64 int_value = 1;
+ optional double double_value = 2;
+ optional string string_value = 3;
+ }
+
+ // The name of the metric. Must be valid UTF-8. Required.
+ optional string name = 1;
+
+ // The value of the metric. Required.
+ optional MetricValue value = 2;
+ }
+
+ // The list of name/value pairs of metrics.
+ repeated Metric metric = 1;
+
+ // Allow multiple sub groups of metrics.
+ repeated MetricsGroup metric_sub_group = 2;
+
+ // Name of the application package associated with the metrics.
+ optional string app_package_name = 3;
+}
+
+// This message contains the specific metrics captured by DrmMetrics. It is
+// used for serializing and logging metrics.
+// next id: 11.
+message DrmFrameworkMetrics {
+ // TODO: Consider using extensions.
+
+ // Attributes are associated with a recorded value. E.g. A counter may
+ // represent a count of an operation returning a specific error code. The
+ // error code will be an attribute.
+ message Attributes {
+ // Reserved for compatibility with logging proto.
+ reserved 2 to 13;
+
+ // A general purpose error code where 0 means OK.
+ optional int32 error_code = 1;
+
+ // Defined at ::android::hardware::drm::V1_0::KeyStatusType;
+ optional uint32 key_status_type = 14;
+
+ // Defined at ::android::hardware::drm::V1_0::EventType;
+ optional uint32 event_type = 15;
+ }
+
+ // The Counter message is used to store a count value with an associated
+ // Attribute.
+ message Counter {
+ optional int64 count = 1;
+ // Represents the attributes associated with this counter instance.
+ optional Attributes attributes = 2;
+ }
+
+ // The DistributionMetric is meant to capture the moments of a normally
+ // distributed (or approximately normal) value.
+ message DistributionMetric {
+ optional double min = 1;
+ optional double max = 2;
+ optional double mean = 3;
+ optional double variance = 4;
+ optional double operation_count = 5;
+
+ // Represents the attributes assocated with this distribution metric
+ // instance.
+ optional Attributes attributes = 6;
+ }
+
+ message SessionLifetime {
+ // Start time of the session in milliseconds since epoch.
+ optional int64 start_time_ms = 1;
+ // End time of the session in milliseconds since epoch.
+ optional int64 end_time_ms = 2;
+ }
+
+ // The count of open session operations. Each instance has a specific error
+ // code associated with it.
+ repeated Counter open_session_counter = 1;
+
+ // The count of close session operations. Each instance has a specific error
+ // code associated with it.
+ repeated Counter close_session_counter = 2;
+
+ // Count and execution time of getKeyRequest calls.
+ repeated DistributionMetric get_key_request_time_us = 3;
+
+ // Count and execution time of provideKeyResponse calls.
+ repeated DistributionMetric provide_key_response_time_us = 4;
+
+ // Count of getProvisionRequest calls.
+ repeated Counter get_provisioning_request_counter = 5;
+
+ // Count of provideProvisionResponse calls.
+ repeated Counter provide_provisioning_response_counter = 6;
+
+ // Count of key status events broken out by status type.
+ repeated Counter key_status_change_counter = 7;
+
+ // Count of events broken out by event type
+ repeated Counter event_callback_counter = 8;
+
+ // Count getPropertyByteArray calls to retrieve the device unique id.
+ repeated Counter get_device_unique_id_counter = 9;
+
+ // Session ids to lifetime (start and end time) map.
+ // Session ids are strings of hex-encoded byte arrays.
+ map<string, SessionLifetime> session_lifetimes = 10;
+}
+
diff --git a/drm/libmediadrm/protos/plugin_metrics.proto b/drm/libmediadrm/protos/plugin_metrics.proto
deleted file mode 100644
index 7e3bcf5..0000000
--- a/drm/libmediadrm/protos/plugin_metrics.proto
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.
- */
-
-syntax = "proto2";
-
-package android.drm_metrics;
-
-// need this if we are using libprotobuf-cpp-2.3.0-lite
-option optimize_for = LITE_RUNTIME;
-
-// The MetricsGroup is a collection of metric name/value pair instances
-// that can be serialized and provided to a caller.
-message MetricsGroup {
- message Metric {
- message MetricValue {
- // Exactly one of the following values must be set.
- optional int64 int_value = 1;
- optional double double_value = 2;
- optional string string_value = 3;
- }
-
- // The name of the metric. Must be valid UTF-8. Required.
- optional string name = 1;
-
- // The value of the metric. Required.
- optional MetricValue value = 2;
- }
-
- // The list of name/value pairs of metrics.
- repeated Metric metric = 1;
-
- // Allow multiple sub groups of metrics.
- repeated MetricsGroup metric_sub_group = 2;
-
- // Name of the application package associated with the metrics.
- optional string app_package_name = 3;
-}
diff --git a/drm/libmediadrm/tests/Android.bp b/drm/libmediadrm/tests/Android.bp
index fdc982d..670d3b9 100644
--- a/drm/libmediadrm/tests/Android.bp
+++ b/drm/libmediadrm/tests/Android.bp
@@ -16,16 +16,23 @@
srcs: ["DrmMetrics_test.cpp"],
shared_libs: [
"android.hardware.drm@1.0",
+ "libbinder",
"liblog",
- "libmediadrm",
+ "libmediadrmmetrics_full",
"libmediametrics",
+ "libprotobuf-cpp-full",
"libutils",
],
- include_dirs: ["frameworks/av/include/media"],
- cflags: [
- "-Werror",
- "-Wall",
+ static_libs: ["libgmock"],
+ include_dirs: [
+ "frameworks/av/include/media",
],
+ cflags: [
+ // Suppress unused parameter and no error options. These cause problems
+ // when using the map type in a proto definition.
+ "-Wno-unused-parameter",
+ "-Wno-error",
+ ]
}
cc_test {
diff --git a/drm/libmediadrm/tests/DrmMetrics_test.cpp b/drm/libmediadrm/tests/DrmMetrics_test.cpp
index d1948b4..fe762c9 100644
--- a/drm/libmediadrm/tests/DrmMetrics_test.cpp
+++ b/drm/libmediadrm/tests/DrmMetrics_test.cpp
@@ -14,27 +14,48 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
-
+#define LOG_TAG "DrmMetricsTest"
#include "DrmMetrics.h"
+#include <binder/PersistableBundle.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/util/message_differencer.h>
+#include <gtest/gtest.h>
+#include <utils/Log.h>
+
+#include "protos/metrics.pb.h"
+
+using ::android::drm_metrics::DrmFrameworkMetrics;
using ::android::hardware::drm::V1_0::EventType;
using ::android::hardware::drm::V1_0::KeyStatusType;
+using ::android::os::PersistableBundle;
+using ::google::protobuf::util::MessageDifferencer;
+using ::google::protobuf::TextFormat;
namespace android {
/**
* Unit tests for the MediaDrmMetrics class.
*/
-class MediaDrmMetricsTest : public ::testing::Test {
+class MediaDrmMetricsTest : public ::testing::Test {};
+
+/**
+ * This derived class mocks the clock for testing purposes.
+ */
+class FakeMediaDrmMetrics : public MediaDrmMetrics {
+ public:
+ FakeMediaDrmMetrics() : MediaDrmMetrics(), time_(0) {};
+
+ int64_t GetCurrentTimeMs() { return time_++; }
+ int64_t time_;
};
TEST_F(MediaDrmMetricsTest, EmptySuccess) {
MediaDrmMetrics metrics;
- MediaAnalyticsItem item;
+ PersistableBundle bundle;
- metrics.Export(&item);
- EXPECT_EQ(0, item.count());
+ metrics.Export(&bundle);
+ EXPECT_TRUE(bundle.empty());
}
TEST_F(MediaDrmMetricsTest, AllValuesSuccessCounts) {
@@ -44,9 +65,9 @@
metrics.mCloseSessionCounter.Increment(OK);
{
- EventTimer<status_t> get_key_request_timer(&metrics.mGetKeyRequestTiming);
+ EventTimer<status_t> get_key_request_timer(&metrics.mGetKeyRequestTimeUs);
EventTimer<status_t> provide_key_response_timer(
- &metrics.mProvideKeyResponseTiming);
+ &metrics.mProvideKeyResponseTimeUs);
get_key_request_timer.SetAttribute(OK);
provide_key_response_timer.SetAttribute(OK);
}
@@ -58,10 +79,10 @@
metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::USABLE);
metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED);
- MediaAnalyticsItem item;
+ PersistableBundle bundle;
- metrics.Export(&item);
- EXPECT_EQ(11, item.count());
+ metrics.Export(&bundle);
+ EXPECT_EQ(11U, bundle.size());
// Verify the list of pairs of int64 metrics.
std::vector<std::pair<std::string, int64_t>> expected_values = {
@@ -75,24 +96,24 @@
{ "drm.mediadrm.event.PROVISION_REQUIRED.count", 1 },
{ "drm.mediadrm.get_device_unique_id.ok.count", 1 }};
for (const auto& expected_pair : expected_values) {
+ String16 key(expected_pair.first.c_str());
int64_t value = -1;
- EXPECT_TRUE(item.getInt64(expected_pair.first.c_str(), &value))
- << "Failed to get " << expected_pair.first;
+ EXPECT_TRUE(bundle.getLong(key, &value))
+ << "Unexpected error retrieviing key: " << key;
EXPECT_EQ(expected_pair.second, value)
- << "Unexpected value for " << expected_pair.first;
+ << "Unexpected value for " << expected_pair.first << ". " << value;
}
// Validate timing values exist.
+ String16 get_key_request_key(
+ "drm.mediadrm.get_key_request.ok.average_time_micros");
+ String16 provide_key_response_key(
+ "drm.mediadrm.provide_key_response.ok.average_time_micros");
int64_t value = -1;
- EXPECT_TRUE(
- item.getInt64("drm.mediadrm.get_key_request.ok.average_time_micros",
- &value));
+ EXPECT_TRUE(bundle.getLong(get_key_request_key, &value));
EXPECT_GE(value, 0);
-
value = -1;
- EXPECT_TRUE(
- item.getInt64("drm.mediadrm.provide_key_response.ok.average_time_micros",
- &value));
+ EXPECT_TRUE(bundle.getLong(provide_key_response_key, &value));
EXPECT_GE(value, 0);
}
@@ -107,9 +128,9 @@
for (status_t s : {OK, UNEXPECTED_NULL}) {
{
- EventTimer<status_t> get_key_request_timer(&metrics.mGetKeyRequestTiming);
+ EventTimer<status_t> get_key_request_timer(&metrics.mGetKeyRequestTimeUs);
EventTimer<status_t> provide_key_response_timer(
- &metrics.mProvideKeyResponseTiming);
+ &metrics.mProvideKeyResponseTimeUs);
get_key_request_timer.SetAttribute(s);
provide_key_response_timer.SetAttribute(s);
}
@@ -133,10 +154,23 @@
metrics.mEventCounter.Increment(EventType::VENDOR_DEFINED);
metrics.mEventCounter.Increment(EventType::SESSION_RECLAIMED);
- MediaAnalyticsItem item;
+ android::Vector<uint8_t> sessionId1;
+ sessionId1.push_back(1);
+ sessionId1.push_back(2);
+ android::Vector<uint8_t> sessionId2;
+ sessionId2.push_back(3);
+ sessionId2.push_back(4);
+ String16 hexSessionId1("0102");
+ String16 hexSessionId2("0304");
- metrics.Export(&item);
- EXPECT_EQ(26, item.count());
+ metrics.SetSessionStart(sessionId1);
+ metrics.SetSessionStart(sessionId2);
+ metrics.SetSessionEnd(sessionId2);
+ metrics.SetSessionEnd(sessionId1);
+
+ PersistableBundle bundle;
+ metrics.Export(&bundle);
+ EXPECT_EQ(35U, bundle.size());
// Verify the list of pairs of int64 metrics.
std::vector<std::pair<std::string, int64_t>> expected_values = {
@@ -165,25 +199,217 @@
{ "drm.mediadrm.event.VENDOR_DEFINED.count", 1 },
{ "drm.mediadrm.event.SESSION_RECLAIMED.count", 1 }};
for (const auto& expected_pair : expected_values) {
+ String16 key(expected_pair.first.c_str());
int64_t value = -1;
- EXPECT_TRUE(item.getInt64(expected_pair.first.c_str(), &value))
- << "Failed to get " << expected_pair.first;
+ EXPECT_TRUE(bundle.getLong(key, &value))
+ << "Unexpected error retrieviing key: " << key;
EXPECT_EQ(expected_pair.second, value)
- << "Unexpected value for " << expected_pair.first;
+ << "Unexpected value for " << expected_pair.first << ". " << value;
+ }
+
+ // Verify the error lists
+ std::vector<std::pair<std::string, std::vector<int64_t>>> expected_vector_values = {
+ { "drm.mediadrm.close_session.error.list", { UNEXPECTED_NULL } },
+ { "drm.mediadrm.get_device_unique_id.error.list", { UNEXPECTED_NULL } },
+ { "drm.mediadrm.get_key_request.error.list", { UNEXPECTED_NULL } },
+ { "drm.mediadrm.get_provision_request.error.list", { UNEXPECTED_NULL } },
+ { "drm.mediadrm.open_session.error.list", { UNEXPECTED_NULL } },
+ { "drm.mediadrm.provide_key_response.error.list", { UNEXPECTED_NULL } },
+ { "drm.mediadrm.provide_provision_response.error.list", { UNEXPECTED_NULL } }};
+ for (const auto& expected_pair : expected_vector_values) {
+ String16 key(expected_pair.first.c_str());
+ std::vector<int64_t> values;
+ EXPECT_TRUE(bundle.getLongVector(key, &values))
+ << "Unexpected error retrieviing key: " << key;
+ for (auto expected : expected_pair.second) {
+ EXPECT_TRUE(std::find(values.begin(), values.end(), expected) != values.end())
+ << "Could not find " << expected << " for key " << expected_pair.first;
+ }
+ }
+
+ // Verify the lifespans
+ PersistableBundle start_times;
+ PersistableBundle end_times;
+ String16 start_time_key("drm.mediadrm.session_start_times_ms");
+ String16 end_time_key("drm.mediadrm.session_end_times_ms");
+ ASSERT_TRUE(bundle.getPersistableBundle(start_time_key, &start_times));
+ ASSERT_TRUE(bundle.getPersistableBundle(end_time_key, &end_times));
+ EXPECT_EQ(2U, start_times.size());
+ EXPECT_EQ(2U, end_times.size());
+ int64_t start_time, end_time;
+ for (const auto& sid : { hexSessionId1, hexSessionId2 }) {
+ start_time = -1;
+ end_time = -1;
+ EXPECT_TRUE(start_times.getLong(sid, &start_time));
+ EXPECT_TRUE(end_times.getLong(sid, &end_time));
+ EXPECT_GT(start_time, 0);
+ EXPECT_GE(end_time, start_time);
}
// Validate timing values exist.
+ String16 get_key_request_key(
+ "drm.mediadrm.get_key_request.ok.average_time_micros");
+ String16 provide_key_response_key(
+ "drm.mediadrm.provide_key_response.ok.average_time_micros");
int64_t value = -1;
- EXPECT_TRUE(
- item.getInt64("drm.mediadrm.get_key_request.ok.average_time_micros",
- &value));
+ EXPECT_TRUE(bundle.getLong(get_key_request_key, &value));
EXPECT_GE(value, 0);
-
value = -1;
- EXPECT_TRUE(
- item.getInt64("drm.mediadrm.provide_key_response.ok.average_time_micros",
- &value));
+ EXPECT_TRUE(bundle.getLong(provide_key_response_key, &value));
EXPECT_GE(value, 0);
}
+
+TEST_F(MediaDrmMetricsTest, CounterValuesProtoSerialization) {
+ MediaDrmMetrics metrics;
+
+ metrics.mOpenSessionCounter.Increment(OK);
+ metrics.mOpenSessionCounter.Increment(UNEXPECTED_NULL);
+ metrics.mCloseSessionCounter.Increment(OK);
+ metrics.mCloseSessionCounter.Increment(UNEXPECTED_NULL);
+
+ metrics.mGetProvisionRequestCounter.Increment(OK);
+ metrics.mGetProvisionRequestCounter.Increment(UNEXPECTED_NULL);
+ metrics.mProvideProvisionResponseCounter.Increment(OK);
+ metrics.mProvideProvisionResponseCounter.Increment(UNEXPECTED_NULL);
+ metrics.mGetDeviceUniqueIdCounter.Increment(OK);
+ metrics.mGetDeviceUniqueIdCounter.Increment(UNEXPECTED_NULL);
+
+ metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::USABLE);
+ metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::EXPIRED);
+ metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::OUTPUTNOTALLOWED);
+ metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::STATUSPENDING);
+ metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::INTERNALERROR);
+ metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED);
+ metrics.mEventCounter.Increment(EventType::KEY_NEEDED);
+ metrics.mEventCounter.Increment(EventType::KEY_EXPIRED);
+ metrics.mEventCounter.Increment(EventType::VENDOR_DEFINED);
+ metrics.mEventCounter.Increment(EventType::SESSION_RECLAIMED);
+
+ std::string serializedMetrics;
+ ASSERT_EQ(OK, metrics.GetSerializedMetrics(&serializedMetrics));
+
+ DrmFrameworkMetrics metricsProto;
+ ASSERT_TRUE(metricsProto.ParseFromString(serializedMetrics));
+
+ std::string expectedMetrics =
+ "open_session_counter { count: 1 attributes { error_code: -0x7FFFFFF8 } } "
+ "open_session_counter { count: 1 attributes { error_code: 0 } } "
+ "close_session_counter { count: 1 attributes { error_code: -0x7FFFFFF8 } } "
+ "close_session_counter { count: 1 attributes { error_code: 0 } } "
+ "get_provisioning_request_counter { count: 1 attributes { error_code: -0x7FFFFFF8 } } "
+ "get_provisioning_request_counter { count: 1 attributes { error_code: 0 } } "
+ "provide_provisioning_response_counter { count: 1 attributes { error_code: -0x7ffffff8 } } "
+ "provide_provisioning_response_counter { count: 1 attributes { error_code: 0 } } "
+ "get_device_unique_id_counter { count: 1 attributes { error_code: -0x7ffffff8 } } "
+ "get_device_unique_id_counter { count: 1 attributes { error_code: 0 } } "
+ "key_status_change_counter { count: 1 attributes { key_status_type: 0 } } "
+ "key_status_change_counter { count: 1 attributes { key_status_type: 1 } } "
+ "key_status_change_counter { count: 1 attributes { key_status_type: 2 } } "
+ "key_status_change_counter { count: 1 attributes { key_status_type: 3 } } "
+ "key_status_change_counter { count: 1 attributes { key_status_type: 4 } } "
+ "event_callback_counter { count: 1 attributes { event_type: 0 } } "
+ "event_callback_counter { count: 1 attributes { event_type: 1 } } "
+ "event_callback_counter { count: 1 attributes { event_type: 2 } } "
+ "event_callback_counter { count: 1 attributes { event_type: 3 } } "
+ "event_callback_counter { count: 1 attributes { event_type: 4 } } ";
+
+ DrmFrameworkMetrics expectedMetricsProto;
+ ASSERT_TRUE(TextFormat::MergeFromString(expectedMetrics, &expectedMetricsProto));
+
+ std::string diffString;
+ MessageDifferencer differ;
+ differ.ReportDifferencesToString(&diffString);
+ ASSERT_TRUE(differ.Compare(expectedMetricsProto, metricsProto))
+ << diffString;
+}
+
+TEST_F(MediaDrmMetricsTest, TimeMetricsProtoSerialization) {
+ MediaDrmMetrics metrics;
+
+ for (status_t s : {OK, UNEXPECTED_NULL}) {
+ double time = 0;
+ for (int i = 0; i < 5; i++) {
+ time += 1.0;
+ metrics.mGetKeyRequestTimeUs.Record(time, s);
+ metrics.mProvideKeyResponseTimeUs.Record(time, s);
+ }
+ }
+
+ std::string serializedMetrics;
+ ASSERT_EQ(OK, metrics.GetSerializedMetrics(&serializedMetrics));
+
+ DrmFrameworkMetrics metricsProto;
+ ASSERT_TRUE(metricsProto.ParseFromString(serializedMetrics));
+
+ std::string expectedMetrics =
+ "get_key_request_timing { "
+ " min: 1 max: 5 mean: 3.5 variance: 1 operation_count: 5 "
+ " attributes { error_code: -0x7FFFFFF8 } "
+ "} "
+ "get_key_request_timing { "
+ " min: 1 max: 5 mean: 3.5 variance: 1 operation_count: 5 "
+ " attributes { error_code: 0 } "
+ "} "
+ "provide_key_response_timing { "
+ " min: 1 max: 5 mean: 3.5 variance: 1 operation_count: 5 "
+ " attributes { error_code: -0x7FFFFFF8 } "
+ "} "
+ "provide_key_response_timing { "
+ " min: 1 max: 5 mean: 3.5 variance: 1 operation_count: 5 "
+ " attributes { error_code: 0 } "
+ "} ";
+
+ DrmFrameworkMetrics expectedMetricsProto;
+ ASSERT_TRUE(TextFormat::MergeFromString(expectedMetrics, &expectedMetricsProto));
+
+ std::string diffString;
+ MessageDifferencer differ;
+ differ.ReportDifferencesToString(&diffString);
+ ASSERT_TRUE(differ.Compare(expectedMetricsProto, metricsProto))
+ << diffString;
+}
+
+TEST_F(MediaDrmMetricsTest, SessionLifetimeProtoSerialization) {
+ // Use the fake so the clock is predictable;
+ FakeMediaDrmMetrics metrics;
+
+ android::Vector<uint8_t> sessionId1;
+ sessionId1.push_back(1);
+ sessionId1.push_back(2);
+ android::Vector<uint8_t> sessionId2;
+ sessionId2.push_back(3);
+ sessionId2.push_back(4);
+
+ metrics.SetSessionStart(sessionId1);
+ metrics.SetSessionStart(sessionId2);
+ metrics.SetSessionEnd(sessionId2);
+ metrics.SetSessionEnd(sessionId1);
+
+ std::string serializedMetrics;
+ ASSERT_EQ(OK, metrics.GetSerializedMetrics(&serializedMetrics));
+
+ DrmFrameworkMetrics metricsProto;
+ ASSERT_TRUE(metricsProto.ParseFromString(serializedMetrics));
+
+ std::string expectedMetrics =
+ "session_lifetimes: { "
+ " key: '0102' "
+ " value { start_time_ms: 0 end_time_ms: 3 } "
+ "} "
+ "session_lifetimes: { "
+ " key: '0304' "
+ " value { start_time_ms: 1 end_time_ms: 2 } "
+ "} ";
+
+ DrmFrameworkMetrics expectedMetricsProto;
+ ASSERT_TRUE(TextFormat::MergeFromString(expectedMetrics, &expectedMetricsProto));
+
+ std::string diffString;
+ MessageDifferencer differ;
+ differ.ReportDifferencesToString(&diffString);
+ ASSERT_TRUE(differ.Compare(expectedMetricsProto, metricsProto))
+ << diffString;
+}
+
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index d921d9e..6b0201a 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -110,6 +110,38 @@
return Status::ERROR_DRM_SESSION_NOT_OPENED;
}
+Status DrmPlugin::getKeyRequestCommon(const hidl_vec<uint8_t>& scope,
+ const hidl_vec<uint8_t>& initData,
+ const hidl_string& mimeType,
+ KeyType keyType,
+ const hidl_vec<KeyValue>& optionalParameters,
+ std::vector<uint8_t> *request,
+ KeyRequestType *keyRequestType,
+ std::string *defaultUrl) {
+ UNUSED(optionalParameters);
+
+ *defaultUrl = "";
+ *keyRequestType = KeyRequestType::UNKNOWN;
+ *request = std::vector<uint8_t>();
+
+ if (scope.size() == 0) {
+ return Status::BAD_VALUE;
+ }
+
+ if (keyType != KeyType::STREAMING) {
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ sp<Session> session = mSessionLibrary->findSession(toVector(scope));
+ if (!session.get()) {
+ return Status::ERROR_DRM_SESSION_NOT_OPENED;
+ }
+
+ Status status = session->getKeyRequest(initData, mimeType, request);
+ *keyRequestType = KeyRequestType::INITIAL;
+ return status;
+}
+
Return<void> DrmPlugin::getKeyRequest(
const hidl_vec<uint8_t>& scope,
const hidl_vec<uint8_t>& initData,
@@ -119,29 +151,16 @@
getKeyRequest_cb _hidl_cb) {
UNUSED(optionalParameters);
- if (scope.size() == 0) {
- // Returns empty keyRequest, unknown keyType and empty defaultUrl
- _hidl_cb(Status::BAD_VALUE, hidl_vec<uint8_t>(),
- KeyRequestType::UNKNOWN, "");
- return Void();
- }
-
- if (keyType != KeyType::STREAMING) {
- _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, hidl_vec<uint8_t>(),
- KeyRequestType::UNKNOWN, "");
- return Void();
- }
-
- sp<Session> session = mSessionLibrary->findSession(toVector(scope));
- if (!session.get()) {
- _hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, hidl_vec<uint8_t>(),
- KeyRequestType::UNKNOWN, "");
- return Void();
- }
-
+ KeyRequestType keyRequestType = KeyRequestType::UNKNOWN;
+ std::string defaultUrl("");
std::vector<uint8_t> request;
- Status status = session->getKeyRequest(initData, mimeType, &request);
- _hidl_cb(status, toHidlVec(request), KeyRequestType::INITIAL, "");
+ Status status = getKeyRequestCommon(
+ scope, initData, mimeType, keyType, optionalParameters,
+ &request, &keyRequestType, &defaultUrl);
+
+ _hidl_cb(status, toHidlVec(request),
+ static_cast<drm::V1_0::KeyRequestType>(keyRequestType),
+ hidl_string(defaultUrl));
return Void();
}
@@ -152,23 +171,16 @@
KeyType keyType,
const hidl_vec<KeyValue>& optionalParameters,
getKeyRequest_1_1_cb _hidl_cb) {
- hidl_string defaultUrl;
- hidl_vec<uint8_t> request;
- ::android::hardware::drm::V1_1::KeyRequestType requestType =
- static_cast<::android::hardware::drm::V1_1::KeyRequestType>(KeyRequestType::UNKNOWN);
- Status status = Status::OK;
+ UNUSED(optionalParameters);
- defaultUrl.clear();
- getKeyRequest(scope, initData, mimeType, keyType, optionalParameters,
- [&](Status statusCode, const hidl_vec<uint8_t>& hResult,
- KeyRequestType hKeyRequestType,
- const hidl_string& hDefaultUrl) {
- defaultUrl = hDefaultUrl;
- request = hResult;
- requestType = static_cast<::android::hardware::drm::V1_1::KeyRequestType>(hKeyRequestType);
- status = statusCode;
- });
- _hidl_cb(status, request, requestType, defaultUrl);
+ KeyRequestType keyRequestType = KeyRequestType::UNKNOWN;
+ std::string defaultUrl("");
+ std::vector<uint8_t> request;
+ Status status = getKeyRequestCommon(
+ scope, initData, mimeType, keyType, optionalParameters,
+ &request, &keyRequestType, &defaultUrl);
+
+ _hidl_cb(status, toHidlVec(request), keyRequestType, hidl_string(defaultUrl));
return Void();
}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
index 5d12598..19baf0b 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
@@ -31,7 +31,6 @@
using ::android::hardware::drm::V1_0::EventType;
using ::android::hardware::drm::V1_0::IDrmPluginListener;
-using ::android::hardware::drm::V1_0::KeyRequestType;
using ::android::hardware::drm::V1_0::KeyStatus;
using ::android::hardware::drm::V1_0::KeyType;
using ::android::hardware::drm::V1_0::KeyValue;
@@ -39,6 +38,8 @@
using ::android::hardware::drm::V1_0::SecureStopId;
using ::android::hardware::drm::V1_0::Status;
using ::android::hardware::drm::V1_1::DrmMetricGroup;
+using ::android::hardware::drm::V1_1::IDrmPlugin;
+using ::android::hardware::drm::V1_1::KeyRequestType;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
@@ -46,7 +47,6 @@
using ::android::hardware::Void;
using ::android::sp;
-
struct DrmPlugin : public IDrmPlugin {
explicit DrmPlugin(SessionLibrary* sessionLibrary);
@@ -335,6 +335,15 @@
Return<Status> setSecurityLevel(const hidl_vec<uint8_t>& sessionId,
SecurityLevel level);
+ Status getKeyRequestCommon(const hidl_vec<uint8_t>& scope,
+ const hidl_vec<uint8_t>& initData,
+ const hidl_string& mimeType,
+ KeyType keyType,
+ const hidl_vec<KeyValue>& optionalParameters,
+ std::vector<uint8_t> *request,
+ KeyRequestType *getKeyRequestType,
+ std::string *defaultUrl);
+
std::vector<KeyValue> mPlayPolicy;
std::map<std::string, std::string> mStringProperties;
std::map<std::string, std::vector<uint8_t> > mByteArrayProperties;
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index 1614ca4..f6c8664 100644
--- a/media/extractors/aac/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -46,7 +46,7 @@
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
+ MediaBufferBase **buffer, const ReadOptions *options = NULL);
protected:
virtual ~AACSource();
@@ -259,7 +259,7 @@
mCurrentTimeUs = 0;
mGroup = new MediaBufferGroup;
- mGroup->add_buffer(new MediaBuffer(kMaxFrameSize));
+ mGroup->add_buffer(MediaBufferBase::Create(kMaxFrameSize));
mStarted = true;
return OK;
@@ -280,7 +280,7 @@
}
status_t AACSource::read(
- MediaBuffer **out, const ReadOptions *options) {
+ MediaBufferBase **out, const ReadOptions *options) {
*out = NULL;
int64_t seekTimeUs;
@@ -303,7 +303,7 @@
return ERROR_END_OF_STREAM;
}
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
status_t err = mGroup->acquire_buffer(&buffer);
if (err != OK) {
return err;
@@ -333,13 +333,20 @@
static MediaExtractor* CreateExtractor(
DataSourceBase *source,
- const sp<AMessage>& meta) {
- return new AACExtractor(source, meta);
+ void *meta) {
+ sp<AMessage> metaData = static_cast<AMessage *>(meta);
+ return new AACExtractor(source, metaData);
+}
+
+static void FreeMeta(void *meta) {
+ if (meta != nullptr) {
+ static_cast<AMessage *>(meta)->decStrong(nullptr);
+ }
}
static MediaExtractor::CreatorFunc Sniff(
- DataSourceBase *source, String8 *mimeType, float *confidence,
- sp<AMessage> *meta) {
+ DataSourceBase *source, float *confidence, void **meta,
+ MediaExtractor::FreeMetaFunc *freeMeta) {
off64_t pos = 0;
for (;;) {
@@ -377,11 +384,14 @@
// ADTS syncword
if ((header[0] == 0xff) && ((header[1] & 0xf6) == 0xf0)) {
- *mimeType = MEDIA_MIMETYPE_AUDIO_AAC_ADTS;
*confidence = 0.2;
- *meta = new AMessage;
- (*meta)->setInt64("offset", pos);
+ AMessage *msg = new AMessage;
+ msg->setInt64("offset", pos);
+ *meta = msg;
+ *freeMeta = &FreeMeta;
+ // ref count will be decreased in FreeMeta.
+ msg->incStrong(nullptr);
return CreateExtractor;
}
diff --git a/media/extractors/amr/AMRExtractor.cpp b/media/extractors/amr/AMRExtractor.cpp
index 547e3f5..59d9ef1 100644
--- a/media/extractors/amr/AMRExtractor.cpp
+++ b/media/extractors/amr/AMRExtractor.cpp
@@ -45,7 +45,7 @@
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
+ MediaBufferBase **buffer, const ReadOptions *options = NULL);
protected:
virtual ~AMRSource();
@@ -122,7 +122,7 @@
mOffsetTableLength(0) {
String8 mimeType;
float confidence;
- if (!SniffAMR(mDataSource, &mimeType, &confidence, NULL)) {
+ if (!SniffAMR(mDataSource, &mimeType, &confidence)) {
return;
}
@@ -233,7 +233,7 @@
mOffset = mIsWide ? 9 : 6;
mCurrentTimeUs = 0;
mGroup = new MediaBufferGroup;
- mGroup->add_buffer(new MediaBuffer(128));
+ mGroup->add_buffer(MediaBufferBase::Create(128));
mStarted = true;
return OK;
@@ -254,7 +254,7 @@
}
status_t AMRSource::read(
- MediaBuffer **out, const ReadOptions *options) {
+ MediaBufferBase **out, const ReadOptions *options) {
*out = NULL;
int64_t seekTimeUs;
@@ -303,7 +303,7 @@
return ERROR_MALFORMED;
}
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
status_t err = mGroup->acquire_buffer(&buffer);
if (err != OK) {
return err;
@@ -339,8 +339,7 @@
////////////////////////////////////////////////////////////////////////////////
bool SniffAMR(
- DataSourceBase *source, String8 *mimeType, float *confidence,
- sp<AMessage> *) {
+ DataSourceBase *source, String8 *mimeType, float *confidence) {
char header[9];
if (source->readAt(0, header, sizeof(header)) != sizeof(header)) {
@@ -348,12 +347,16 @@
}
if (!memcmp(header, "#!AMR\n", 6)) {
- *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_NB;
+ if (mimeType != nullptr) {
+ *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_NB;
+ }
*confidence = 0.5;
return true;
} else if (!memcmp(header, "#!AMR-WB\n", 9)) {
- *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_WB;
+ if (mimeType != nullptr) {
+ *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_WB;
+ }
*confidence = 0.5;
return true;
@@ -373,13 +376,13 @@
"AMR Extractor",
[](
DataSourceBase *source,
- String8 *mimeType,
float *confidence,
- sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
- if (SniffAMR(source, mimeType, confidence, meta)) {
+ void **,
+ MediaExtractor::FreeMetaFunc *) -> MediaExtractor::CreatorFunc {
+ if (SniffAMR(source, nullptr, confidence)) {
return [](
DataSourceBase *source,
- const sp<AMessage>& meta __unused) -> MediaExtractor* {
+ void *) -> MediaExtractor* {
return new AMRExtractor(source);};
}
return NULL;
diff --git a/media/extractors/amr/AMRExtractor.h b/media/extractors/amr/AMRExtractor.h
index d6d49f2..b8b44ea 100644
--- a/media/extractors/amr/AMRExtractor.h
+++ b/media/extractors/amr/AMRExtractor.h
@@ -55,8 +55,7 @@
};
bool SniffAMR(
- DataSourceBase *source, String8 *mimeType, float *confidence,
- sp<AMessage> *);
+ DataSourceBase *source, String8 *mimeType, float *confidence);
} // namespace android
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index 8dbb5a1..2c5e43e 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -31,7 +31,7 @@
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferBase.h>
namespace android {
@@ -173,7 +173,7 @@
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
+ MediaBufferBase **buffer, const ReadOptions *options = NULL);
protected:
virtual ~FLACSource();
@@ -232,10 +232,10 @@
// media buffers
void allocateBuffers();
void releaseBuffers();
- MediaBuffer *readBuffer() {
+ MediaBufferBase *readBuffer() {
return readBuffer(false, 0LL);
}
- MediaBuffer *readBuffer(FLAC__uint64 sample) {
+ MediaBufferBase *readBuffer(FLAC__uint64 sample) {
return readBuffer(true, sample);
}
@@ -274,7 +274,7 @@
FLAC__StreamDecoderErrorStatus mErrorStatus;
status_t init();
- MediaBuffer *readBuffer(bool doSeek, FLAC__uint64 sample);
+ MediaBufferBase *readBuffer(bool doSeek, FLAC__uint64 sample);
// no copy constructor or assignment
FLACParser(const FLACParser &);
@@ -763,7 +763,7 @@
CHECK(mGroup == NULL);
mGroup = new MediaBufferGroup;
mMaxBufferSize = getMaxBlockSize() * getChannels() * sizeof(short);
- mGroup->add_buffer(new MediaBuffer(mMaxBufferSize));
+ mGroup->add_buffer(MediaBufferBase::Create(mMaxBufferSize));
}
void FLACParser::releaseBuffers()
@@ -773,7 +773,7 @@
mGroup = NULL;
}
-MediaBuffer *FLACParser::readBuffer(bool doSeek, FLAC__uint64 sample)
+MediaBufferBase *FLACParser::readBuffer(bool doSeek, FLAC__uint64 sample)
{
mWriteRequested = true;
mWriteCompleted = false;
@@ -810,7 +810,7 @@
}
// acquire a media buffer
CHECK(mGroup != NULL);
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
status_t err = mGroup->acquire_buffer(&buffer);
if (err != OK) {
return NULL;
@@ -881,9 +881,9 @@
}
status_t FLACSource::read(
- MediaBuffer **outBuffer, const ReadOptions *options)
+ MediaBufferBase **outBuffer, const ReadOptions *options)
{
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
// process an optional seek request
int64_t seekTimeUs;
ReadOptions::SeekMode mode;
@@ -968,9 +968,7 @@
// Sniffer
-bool SniffFLAC(
- DataSourceBase *source, String8 *mimeType, float *confidence,
- sp<AMessage> *)
+bool SniffFLAC(DataSourceBase *source, float *confidence)
{
// first 4 is the signature word
// second 4 is the sizeof STREAMINFO
@@ -983,7 +981,6 @@
return false;
}
- *mimeType = MEDIA_MIMETYPE_AUDIO_FLAC;
*confidence = 0.5;
return true;
@@ -1001,13 +998,13 @@
"FLAC Extractor",
[](
DataSourceBase *source,
- String8 *mimeType,
float *confidence,
- sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
- if (SniffFLAC(source, mimeType, confidence, meta)) {
+ void **,
+ MediaExtractor::FreeMetaFunc *) -> MediaExtractor::CreatorFunc {
+ if (SniffFLAC(source, confidence)) {
return [](
DataSourceBase *source,
- const sp<AMessage>& meta __unused) -> MediaExtractor* {
+ void *) -> MediaExtractor* {
return new FLACExtractor(source);};
}
return NULL;
diff --git a/media/extractors/flac/FLACExtractor.h b/media/extractors/flac/FLACExtractor.h
index ef07212..f41d878 100644
--- a/media/extractors/flac/FLACExtractor.h
+++ b/media/extractors/flac/FLACExtractor.h
@@ -56,8 +56,7 @@
};
-bool SniffFLAC(DataSourceBase *source, String8 *mimeType,
- float *confidence, sp<AMessage> *);
+bool SniffFLAC(DataSourceBase *source, float *confidence);
} // namespace android
diff --git a/media/extractors/midi/MidiExtractor.cpp b/media/extractors/midi/MidiExtractor.cpp
index 711c6a5..cf446db 100644
--- a/media/extractors/midi/MidiExtractor.cpp
+++ b/media/extractors/midi/MidiExtractor.cpp
@@ -30,7 +30,7 @@
namespace android {
-// how many Sonivox output buffers to aggregate into one MediaBuffer
+// how many Sonivox output buffers to aggregate into one MediaBufferBase
static const int NUM_COMBINE_BUFFERS = 4;
class MidiSource : public MediaSourceBase {
@@ -45,7 +45,7 @@
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
+ MediaBufferBase **buffer, const ReadOptions *options = NULL);
protected:
virtual ~MidiSource();
@@ -114,10 +114,10 @@
}
status_t MidiSource::read(
- MediaBuffer **outBuffer, const ReadOptions *options)
+ MediaBufferBase **outBuffer, const ReadOptions *options)
{
ALOGV("MidiSource::read");
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
// process an optional seek request
int64_t seekTimeUs;
ReadOptions::SeekMode mode;
@@ -207,7 +207,7 @@
int bufsize = sizeof(EAS_PCM)
* mEasConfig->mixBufferSize * mEasConfig->numChannels * NUM_COMBINE_BUFFERS;
ALOGV("using %d byte buffer", bufsize);
- mGroup->add_buffer(new MediaBuffer(bufsize));
+ mGroup->add_buffer(MediaBufferBase::Create(bufsize));
return OK;
}
@@ -223,13 +223,13 @@
return result == EAS_SUCCESS ? OK : UNKNOWN_ERROR;
}
-MediaBuffer* MidiEngine::readBuffer() {
+MediaBufferBase* MidiEngine::readBuffer() {
EAS_STATE state;
EAS_State(mEasData, mEasHandle, &state);
if ((state == EAS_STATE_STOPPED) || (state == EAS_STATE_ERROR)) {
return NULL;
}
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
status_t err = mGroup->acquire_buffer(&buffer);
if (err != OK) {
ALOGE("readBuffer: no buffer");
@@ -307,13 +307,10 @@
// Sniffer
-bool SniffMidi(
- DataSourceBase *source, String8 *mimeType, float *confidence,
- sp<AMessage> *)
+bool SniffMidi(DataSourceBase *source, float *confidence)
{
sp<MidiEngine> p = new MidiEngine(source, NULL, NULL);
if (p->initCheck() == OK) {
- *mimeType = MEDIA_MIMETYPE_AUDIO_MIDI;
*confidence = 0.8;
ALOGV("SniffMidi: yes");
return true;
@@ -334,13 +331,13 @@
"MIDI Extractor",
[](
DataSourceBase *source,
- String8 *mimeType,
float *confidence,
- sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
- if (SniffMidi(source, mimeType, confidence, meta)) {
+ void **,
+ MediaExtractor::FreeMetaFunc *) -> MediaExtractor::CreatorFunc {
+ if (SniffMidi(source, confidence)) {
return [](
DataSourceBase *source,
- const sp<AMessage>& meta __unused) -> MediaExtractor* {
+ void *) -> MediaExtractor* {
return new MidiExtractor(source);};
}
return NULL;
diff --git a/media/extractors/midi/MidiExtractor.h b/media/extractors/midi/MidiExtractor.h
index 91efd06..4274513 100644
--- a/media/extractors/midi/MidiExtractor.h
+++ b/media/extractors/midi/MidiExtractor.h
@@ -19,7 +19,7 @@
#include <media/DataSourceBase.h>
#include <media/MediaExtractor.h>
-#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferBase.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/MidiIoWrapper.h>
#include <utils/String8.h>
@@ -39,7 +39,7 @@
status_t allocateBuffers();
status_t releaseBuffers();
status_t seekTo(int64_t positionUs);
- MediaBuffer* readBuffer();
+ MediaBufferBase* readBuffer();
private:
sp<MidiIoWrapper> mIoWrapper;
MediaBufferGroup *mGroup;
@@ -87,8 +87,7 @@
};
-bool SniffMidi(DataSourceBase *source, String8 *mimeType,
- float *confidence, sp<AMessage> *);
+bool SniffMidi(DataSourceBase *source, float *confidence);
} // namespace android
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index f61f7c7..65988d3 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -29,7 +29,7 @@
#include <media/stagefright/foundation/ByteUtils.h>
#include <media/stagefright/foundation/ColorUtils.h>
#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferBase.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -130,7 +130,7 @@
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options);
+ MediaBufferBase **buffer, const ReadOptions *options);
protected:
virtual ~MatroskaSource();
@@ -150,11 +150,11 @@
BlockIterator mBlockIter;
ssize_t mNALSizeLen; // for type AVC or HEVC
- List<MediaBuffer *> mPendingFrames;
+ List<MediaBufferBase *> mPendingFrames;
status_t advance();
- status_t setWebmBlockCryptoInfo(MediaBuffer *mbuf);
+ status_t setWebmBlockCryptoInfo(MediaBufferBase *mbuf);
status_t readBlock();
void clearPendingFrames();
@@ -568,7 +568,7 @@
void MatroskaSource::clearPendingFrames() {
while (!mPendingFrames.empty()) {
- MediaBuffer *frame = *mPendingFrames.begin();
+ MediaBufferBase *frame = *mPendingFrames.begin();
mPendingFrames.erase(mPendingFrames.begin());
frame->release();
@@ -576,7 +576,7 @@
}
}
-status_t MatroskaSource::setWebmBlockCryptoInfo(MediaBuffer *mbuf) {
+status_t MatroskaSource::setWebmBlockCryptoInfo(MediaBufferBase *mbuf) {
if (mbuf->range_length() < 1 || mbuf->range_length() - 1 > INT32_MAX) {
// 1-byte signal
return ERROR_MALFORMED;
@@ -662,7 +662,7 @@
}
len += trackInfo->mHeaderLen;
- MediaBuffer *mbuf = new MediaBuffer(len);
+ MediaBufferBase *mbuf = MediaBufferBase::Create(len);
uint8_t *data = static_cast<uint8_t *>(mbuf->data());
if (trackInfo->mHeader) {
memcpy(data, trackInfo->mHeader, trackInfo->mHeaderLen);
@@ -695,7 +695,7 @@
}
status_t MatroskaSource::read(
- MediaBuffer **out, const ReadOptions *options) {
+ MediaBufferBase **out, const ReadOptions *options) {
*out = NULL;
int64_t targetSampleTimeUs = -1ll;
@@ -731,7 +731,7 @@
}
}
- MediaBuffer *frame = *mPendingFrames.begin();
+ MediaBufferBase *frame = *mPendingFrames.begin();
mPendingFrames.erase(mPendingFrames.begin());
if ((mType != AVC && mType != HEVC) || mNALSizeLen == 0) {
@@ -760,7 +760,7 @@
size_t srcSize = frame->range_length();
size_t dstSize = 0;
- MediaBuffer *buffer = NULL;
+ MediaBufferBase *buffer = NULL;
uint8_t *dstPtr = NULL;
for (int32_t pass = 0; pass < 2; ++pass) {
@@ -820,7 +820,7 @@
// each 4-byte nal size with a 4-byte start code
buffer = frame;
} else {
- buffer = new MediaBuffer(dstSize);
+ buffer = MediaBufferBase::Create(dstSize);
}
int64_t timeUs;
@@ -1548,8 +1548,7 @@
}
bool SniffMatroska(
- DataSourceBase *source, String8 *mimeType, float *confidence,
- sp<AMessage> *) {
+ DataSourceBase *source, float *confidence) {
DataSourceBaseReader reader(source);
mkvparser::EBMLHeader ebmlHeader;
long long pos;
@@ -1557,7 +1556,6 @@
return false;
}
- mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MATROSKA);
*confidence = 0.6;
return true;
@@ -1575,13 +1573,13 @@
"Matroska Extractor",
[](
DataSourceBase *source,
- String8 *mimeType,
float *confidence,
- sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
- if (SniffMatroska(source, mimeType, confidence, meta)) {
+ void **,
+ MediaExtractor::FreeMetaFunc *) -> MediaExtractor::CreatorFunc {
+ if (SniffMatroska(source, confidence)) {
return [](
DataSourceBase *source,
- const sp<AMessage>& meta __unused) -> MediaExtractor* {
+ void *) -> MediaExtractor* {
return new MatroskaExtractor(source);};
}
return NULL;
diff --git a/media/extractors/mp3/MP3Extractor.cpp b/media/extractors/mp3/MP3Extractor.cpp
index 25d4deb..90ee653 100644
--- a/media/extractors/mp3/MP3Extractor.cpp
+++ b/media/extractors/mp3/MP3Extractor.cpp
@@ -30,7 +30,7 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferBase.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
@@ -222,7 +222,7 @@
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
+ MediaBufferBase **buffer, const ReadOptions *options = NULL);
protected:
virtual ~MP3Source();
@@ -463,7 +463,7 @@
mGroup = new MediaBufferGroup;
- mGroup->add_buffer(new MediaBuffer(kMaxFrameSize));
+ mGroup->add_buffer(MediaBufferBase::Create(kMaxFrameSize));
mCurrentPos = mFirstFramePos;
mCurrentTimeUs = 0;
@@ -492,7 +492,7 @@
}
status_t MP3Source::read(
- MediaBuffer **out, const ReadOptions *options) {
+ MediaBufferBase **out, const ReadOptions *options) {
*out = NULL;
int64_t seekTimeUs;
@@ -522,7 +522,7 @@
mSamplesRead = 0;
}
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
status_t err = mGroup->acquire_buffer(&buffer);
if (err != OK) {
return err;
@@ -668,13 +668,20 @@
static MediaExtractor* CreateExtractor(
DataSourceBase *source,
- const sp<AMessage>& meta) {
- return new MP3Extractor(source, meta);
+ void *meta) {
+ sp<AMessage> metaData = static_cast<AMessage *>(meta);
+ return new MP3Extractor(source, metaData);
+}
+
+static void FreeMeta(void *meta) {
+ if (meta != nullptr) {
+ static_cast<AMessage *>(meta)->decStrong(nullptr);
+ }
}
static MediaExtractor::CreatorFunc Sniff(
- DataSourceBase *source, String8 *mimeType,
- float *confidence, sp<AMessage> *meta) {
+ DataSourceBase *source, float *confidence, void **meta,
+ MediaExtractor::FreeMetaFunc *freeMeta) {
off64_t pos = 0;
off64_t post_id3_pos;
uint32_t header;
@@ -691,12 +698,15 @@
return NULL;
}
- *meta = new AMessage;
- (*meta)->setInt64("offset", pos);
- (*meta)->setInt32("header", header);
- (*meta)->setInt64("post-id3-offset", post_id3_pos);
+ AMessage *msg = new AMessage;
+ msg->setInt64("offset", pos);
+ msg->setInt32("header", header);
+ msg->setInt64("post-id3-offset", post_id3_pos);
+ *meta = msg;
+ *freeMeta = &FreeMeta;
+ // ref count will be decreased in FreeMeta.
+ msg->incStrong(nullptr);
- *mimeType = MEDIA_MIMETYPE_AUDIO_MPEG;
*confidence = 0.2f;
return CreateExtractor;
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 30dda13..40c84a5 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -41,7 +41,7 @@
#include <media/stagefright/foundation/ColorUtils.h>
#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferBase.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
@@ -83,9 +83,9 @@
virtual sp<MetaData> getFormat();
- virtual status_t read(MediaBuffer **buffer, const ReadOptions *options = NULL);
+ virtual status_t read(MediaBufferBase **buffer, const ReadOptions *options = NULL);
virtual bool supportNonblockingRead() { return true; }
- virtual status_t fragmentedRead(MediaBuffer **buffer, const ReadOptions *options = NULL);
+ virtual status_t fragmentedRead(MediaBufferBase **buffer, const ReadOptions *options = NULL);
virtual ~MPEG4Source();
@@ -128,7 +128,7 @@
MediaBufferGroup *mGroup;
- MediaBuffer *mBuffer;
+ MediaBufferBase *mBuffer;
bool mWantsNALFragments;
@@ -354,9 +354,7 @@
mPreferHeif(mime != NULL && !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_HEIF)),
mFirstTrack(NULL),
mLastTrack(NULL),
- mFileMetaData(new MetaData),
- mFirstSINF(NULL),
- mIsDrm(false) {
+ mFileMetaData(new MetaData) {
ALOGV("mime=%s, mPreferHeif=%d", mime, mPreferHeif);
}
@@ -370,15 +368,6 @@
}
mFirstTrack = mLastTrack = NULL;
- SINF *sinf = mFirstSINF;
- while (sinf) {
- SINF *next = sinf->next;
- delete[] sinf->IPMPData;
- delete sinf;
- sinf = next;
- }
- mFirstSINF = NULL;
-
for (size_t i = 0; i < mPssh.size(); i++) {
delete [] mPssh[i].data;
}
@@ -672,177 +661,6 @@
return mInitCheck;
}
-char* MPEG4Extractor::getDrmTrackInfo(size_t trackID, int *len) {
- if (mFirstSINF == NULL) {
- return NULL;
- }
-
- SINF *sinf = mFirstSINF;
- while (sinf && (trackID != sinf->trackID)) {
- sinf = sinf->next;
- }
-
- if (sinf == NULL) {
- return NULL;
- }
-
- *len = sinf->len;
- return sinf->IPMPData;
-}
-
-// Reads an encoded integer 7 bits at a time until it encounters the high bit clear.
-static int32_t readSize(off64_t offset,
- DataSourceBase *DataSourceBase, uint8_t *numOfBytes) {
- uint32_t size = 0;
- uint8_t data;
- bool moreData = true;
- *numOfBytes = 0;
-
- while (moreData) {
- if (DataSourceBase->readAt(offset, &data, 1) < 1) {
- return -1;
- }
- offset ++;
- moreData = (data >= 128) ? true : false;
- size = (size << 7) | (data & 0x7f); // Take last 7 bits
- (*numOfBytes) ++;
- }
-
- return size;
-}
-
-status_t MPEG4Extractor::parseDrmSINF(
- off64_t * /* offset */, off64_t data_offset) {
- uint8_t updateIdTag;
- if (mDataSource->readAt(data_offset, &updateIdTag, 1) < 1) {
- return ERROR_IO;
- }
- data_offset ++;
-
- if (0x01/*OBJECT_DESCRIPTOR_UPDATE_ID_TAG*/ != updateIdTag) {
- return ERROR_MALFORMED;
- }
-
- uint8_t numOfBytes;
- int32_t size = readSize(data_offset, mDataSource, &numOfBytes);
- if (size < 0) {
- return ERROR_IO;
- }
- data_offset += numOfBytes;
-
- while(size >= 11 ) {
- uint8_t descriptorTag;
- if (mDataSource->readAt(data_offset, &descriptorTag, 1) < 1) {
- return ERROR_IO;
- }
- data_offset ++;
-
- if (0x11/*OBJECT_DESCRIPTOR_ID_TAG*/ != descriptorTag) {
- return ERROR_MALFORMED;
- }
-
- uint8_t buffer[8];
- //ObjectDescriptorID and ObjectDescriptor url flag
- if (mDataSource->readAt(data_offset, buffer, 2) < 2) {
- return ERROR_IO;
- }
- data_offset += 2;
-
- if ((buffer[1] >> 5) & 0x0001) { //url flag is set
- return ERROR_MALFORMED;
- }
-
- if (mDataSource->readAt(data_offset, buffer, 8) < 8) {
- return ERROR_IO;
- }
- data_offset += 8;
-
- if ((0x0F/*ES_ID_REF_TAG*/ != buffer[1])
- || ( 0x0A/*IPMP_DESCRIPTOR_POINTER_ID_TAG*/ != buffer[5])) {
- return ERROR_MALFORMED;
- }
-
- SINF *sinf = new SINF;
- sinf->trackID = U16_AT(&buffer[3]);
- sinf->IPMPDescriptorID = buffer[7];
- sinf->next = mFirstSINF;
- mFirstSINF = sinf;
-
- size -= (8 + 2 + 1);
- }
-
- if (size != 0) {
- return ERROR_MALFORMED;
- }
-
- if (mDataSource->readAt(data_offset, &updateIdTag, 1) < 1) {
- return ERROR_IO;
- }
- data_offset ++;
-
- if(0x05/*IPMP_DESCRIPTOR_UPDATE_ID_TAG*/ != updateIdTag) {
- return ERROR_MALFORMED;
- }
-
- size = readSize(data_offset, mDataSource, &numOfBytes);
- if (size < 0) {
- return ERROR_IO;
- }
- data_offset += numOfBytes;
-
- while (size > 0) {
- uint8_t tag;
- int32_t dataLen;
- if (mDataSource->readAt(data_offset, &tag, 1) < 1) {
- return ERROR_IO;
- }
- data_offset ++;
-
- if (0x0B/*IPMP_DESCRIPTOR_ID_TAG*/ == tag) {
- uint8_t id;
- dataLen = readSize(data_offset, mDataSource, &numOfBytes);
- if (dataLen < 0) {
- return ERROR_IO;
- } else if (dataLen < 4) {
- return ERROR_MALFORMED;
- }
- data_offset += numOfBytes;
-
- if (mDataSource->readAt(data_offset, &id, 1) < 1) {
- return ERROR_IO;
- }
- data_offset ++;
-
- SINF *sinf = mFirstSINF;
- while (sinf && (sinf->IPMPDescriptorID != id)) {
- sinf = sinf->next;
- }
- if (sinf == NULL) {
- return ERROR_MALFORMED;
- }
- sinf->len = dataLen - 3;
- sinf->IPMPData = new (std::nothrow) char[sinf->len];
- if (sinf->IPMPData == NULL) {
- return ERROR_MALFORMED;
- }
- data_offset += 2;
-
- if (mDataSource->readAt(data_offset, sinf->IPMPData, sinf->len) < sinf->len) {
- return ERROR_IO;
- }
- data_offset += sinf->len;
-
- size -= (dataLen + numOfBytes + 1);
- }
- }
-
- if (size != 0) {
- return ERROR_MALFORMED;
- }
-
- return UNKNOWN_ERROR; // Return a dummy error.
-}
-
struct PathAdder {
PathAdder(Vector<uint32_t> *path, uint32_t chunkType)
: mPath(path) {
@@ -1144,11 +962,7 @@
} else if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
mInitCheck = OK;
- if (!mIsDrm) {
- return UNKNOWN_ERROR; // Return a dummy error.
- } else {
- return OK;
- }
+ return UNKNOWN_ERROR; // Return a dummy error.
}
break;
}
@@ -1596,7 +1410,7 @@
}
if (chunk_type != FOURCC('e', 'n', 'c', 'a')) {
- // if the chunk type is enca, we'll get the type from the sinf/frma box later
+ // if the chunk type is enca, we'll get the type from the frma box later
mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
AdjustChannelsAndRate(chunk_type, &num_channels, &sample_rate);
}
@@ -1656,7 +1470,7 @@
return ERROR_MALFORMED;
if (chunk_type != FOURCC('e', 'n', 'c', 'v')) {
- // if the chunk type is encv, we'll get the type from the sinf/frma box later
+ // if the chunk type is encv, we'll get the type from the frma box later
mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
}
mLastTrack->meta->setInt32(kKeyWidth, width);
@@ -2278,20 +2092,10 @@
case FOURCC('m', 'd', 'a', 't'):
{
- ALOGV("mdat chunk, drm: %d", mIsDrm);
-
mMdatFound = true;
- if (!mIsDrm) {
- *offset += chunk_size;
- break;
- }
-
- if (chunk_size < 8) {
- return ERROR_MALFORMED;
- }
-
- return parseDrmSINF(offset, data_offset);
+ *offset += chunk_size;
+ break;
}
case FOURCC('h', 'd', 'l', 'r'):
@@ -4681,7 +4485,7 @@
}
status_t MPEG4Source::read(
- MediaBuffer **out, const ReadOptions *options) {
+ MediaBufferBase **out, const ReadOptions *options) {
Mutex::Autolock autoLock(mLock);
CHECK(mStarted);
@@ -4906,7 +4710,7 @@
return ERROR_MALFORMED;
}
- MediaBuffer *clone = mBuffer->clone();
+ MediaBufferBase *clone = mBuffer->clone();
CHECK(clone != NULL);
clone->set_range(mBuffer->range_offset() + mNALLengthSize, nal_size);
@@ -5026,7 +4830,7 @@
}
status_t MPEG4Source::fragmentedRead(
- MediaBuffer **out, const ReadOptions *options) {
+ MediaBufferBase **out, const ReadOptions *options) {
ALOGV("MPEG4Source::fragmentedRead");
@@ -5230,7 +5034,7 @@
return ERROR_MALFORMED;
}
- MediaBuffer *clone = mBuffer->clone();
+ MediaBufferBase *clone = mBuffer->clone();
CHECK(clone != NULL);
clone->set_range(mBuffer->range_offset() + mNALLengthSize, nal_size);
@@ -5382,8 +5186,7 @@
return NULL;
}
-static bool LegacySniffMPEG4(
- DataSourceBase *source, String8 *mimeType, float *confidence) {
+static bool LegacySniffMPEG4(DataSourceBase *source, float *confidence) {
uint8_t header[8];
ssize_t n = source->readAt(4, header, sizeof(header));
@@ -5399,7 +5202,6 @@
|| !memcmp(header, "ftypkddi", 8) || !memcmp(header, "ftypM4VP", 8)
|| !memcmp(header, "ftypmif1", 8) || !memcmp(header, "ftypheic", 8)
|| !memcmp(header, "ftypmsf1", 8) || !memcmp(header, "ftyphevc", 8)) {
- *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
*confidence = 0.4;
return true;
@@ -5449,9 +5251,7 @@
// Also try to identify where this file's metadata ends
// (end of the 'moov' atom) and report it to the caller as part of
// the metadata.
-static bool BetterSniffMPEG4(
- DataSourceBase *source, String8 *mimeType, float *confidence,
- sp<AMessage> *meta) {
+static bool BetterSniffMPEG4(DataSourceBase *source, float *confidence) {
// We scan up to 128 bytes to identify this file as an MP4.
static const off64_t kMaxScanOffset = 128ll;
@@ -5553,35 +5353,23 @@
return false;
}
- *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
*confidence = 0.4f;
- if (moovAtomEndOffset >= 0) {
- *meta = new AMessage;
- (*meta)->setInt64("meta-data-size", moovAtomEndOffset);
-
- ALOGV("found metadata size: %lld", (long long)moovAtomEndOffset);
- }
-
return true;
}
-static MediaExtractor* CreateExtractor(
- DataSourceBase *source,
- const sp<AMessage>& meta __unused) {
+static MediaExtractor* CreateExtractor(DataSourceBase *source, void *) {
return new MPEG4Extractor(source);
}
static MediaExtractor::CreatorFunc Sniff(
- DataSourceBase *source,
- String8 *mimeType,
- float *confidence,
- sp<AMessage> *meta) {
- if (BetterSniffMPEG4(source, mimeType, confidence, meta)) {
+ DataSourceBase *source, float *confidence, void **,
+ MediaExtractor::FreeMetaFunc *) {
+ if (BetterSniffMPEG4(source, confidence)) {
return CreateExtractor;
}
- if (LegacySniffMPEG4(source, mimeType, confidence)) {
+ if (LegacySniffMPEG4(source, confidence)) {
ALOGW("Identified supported mpeg4 through LegacySniffMPEG4.");
return CreateExtractor;
}
diff --git a/media/extractors/mp4/MPEG4Extractor.h b/media/extractors/mp4/MPEG4Extractor.h
index 644c430..5c86345 100644
--- a/media/extractors/mp4/MPEG4Extractor.h
+++ b/media/extractors/mp4/MPEG4Extractor.h
@@ -63,9 +63,6 @@
virtual uint32_t flags() const;
virtual const char * name() { return "MPEG4Extractor"; }
- // for DRM
- virtual char* getDrmTrackInfo(size_t trackID, int *len);
-
protected:
virtual ~MPEG4Extractor();
@@ -131,21 +128,8 @@
static status_t verifyTrack(Track *track);
- struct SINF {
- SINF *next;
- uint16_t trackID;
- uint8_t IPMPDescriptorID;
- ssize_t len;
- char *IPMPData;
- };
-
- SINF *mFirstSINF;
-
- bool mIsDrm;
sp<ItemTable> mItemTable;
- status_t parseDrmSINF(off64_t *offset, off64_t data_offset);
-
status_t parseTrackHeader(off64_t data_offset, off64_t data_size);
status_t parseSegmentIndex(off64_t data_offset, size_t data_size);
diff --git a/media/extractors/mpeg2/ExtractorBundle.cpp b/media/extractors/mpeg2/ExtractorBundle.cpp
index 443d685..8a0fa03 100644
--- a/media/extractors/mpeg2/ExtractorBundle.cpp
+++ b/media/extractors/mpeg2/ExtractorBundle.cpp
@@ -35,18 +35,18 @@
"MPEG2-PS/TS Extractor",
[](
DataSourceBase *source,
- String8 *mimeType,
float *confidence,
- sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
- if (SniffMPEG2TS(source, mimeType, confidence, meta)) {
+ void **,
+ MediaExtractor::FreeMetaFunc *) -> MediaExtractor::CreatorFunc {
+ if (SniffMPEG2TS(source, confidence)) {
return [](
DataSourceBase *source,
- const sp<AMessage>& meta __unused) -> MediaExtractor* {
+ void *) -> MediaExtractor* {
return new MPEG2TSExtractor(source);};
- } else if (SniffMPEG2PS(source, mimeType, confidence, meta)) {
+ } else if (SniffMPEG2PS(source, confidence)) {
return [](
DataSourceBase *source,
- const sp<AMessage>& meta __unused) -> MediaExtractor* {
+ void *) -> MediaExtractor* {
return new MPEG2PSExtractor(source);};
}
return NULL;
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.cpp b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
index 697e44f..c2de6e7 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
@@ -49,7 +49,7 @@
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options);
+ MediaBufferBase **buffer, const ReadOptions *options);
protected:
virtual ~Track();
@@ -80,7 +80,7 @@
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options);
+ MediaBufferBase **buffer, const ReadOptions *options);
protected:
virtual ~WrappedTrack();
@@ -659,7 +659,7 @@
}
status_t MPEG2PSExtractor::Track::read(
- MediaBuffer **buffer, const ReadOptions *options) {
+ MediaBufferBase **buffer, const ReadOptions *options) {
if (mSource == NULL) {
return NO_INIT;
}
@@ -744,15 +744,14 @@
}
status_t MPEG2PSExtractor::WrappedTrack::read(
- MediaBuffer **buffer, const ReadOptions *options) {
+ MediaBufferBase **buffer, const ReadOptions *options) {
return mTrack->read(buffer, options);
}
////////////////////////////////////////////////////////////////////////////////
bool SniffMPEG2PS(
- DataSourceBase *source, String8 *mimeType, float *confidence,
- sp<AMessage> *) {
+ DataSourceBase *source, float *confidence) {
uint8_t header[5];
if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
return false;
@@ -764,8 +763,6 @@
*confidence = 0.25f; // Slightly larger than .mp3 extractor's confidence
- mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2PS);
-
return true;
}
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.h b/media/extractors/mpeg2/MPEG2PSExtractor.h
index adf719a..2541f4d 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.h
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.h
@@ -71,9 +71,7 @@
DISALLOW_EVIL_CONSTRUCTORS(MPEG2PSExtractor);
};
-bool SniffMPEG2PS(
- DataSourceBase *source, String8 *mimeType, float *confidence,
- sp<AMessage> *);
+bool SniffMPEG2PS(DataSourceBase *source, float *confidence);
} // namespace android
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.cpp b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
index a8a366b..7887a7c 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
@@ -61,7 +61,7 @@
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
+ MediaBufferBase **buffer, const ReadOptions *options = NULL);
private:
MPEG2TSExtractor *mExtractor;
@@ -99,7 +99,7 @@
}
status_t MPEG2TSSource::read(
- MediaBuffer **out, const ReadOptions *options) {
+ MediaBufferBase **out, const ReadOptions *options) {
*out = NULL;
int64_t seekTimeUs;
@@ -645,9 +645,7 @@
////////////////////////////////////////////////////////////////////////////////
-bool SniffMPEG2TS(
- DataSourceBase *source, String8 *mimeType, float *confidence,
- sp<AMessage> *) {
+bool SniffMPEG2TS(DataSourceBase *source, float *confidence) {
for (int i = 0; i < 5; ++i) {
char header;
if (source->readAt(kTSPacketSize * i, &header, 1) != 1
@@ -657,7 +655,6 @@
}
*confidence = 0.1f;
- mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
return true;
}
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.h b/media/extractors/mpeg2/MPEG2TSExtractor.h
index fc15501..df07fac 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.h
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.h
@@ -99,9 +99,7 @@
DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSExtractor);
};
-bool SniffMPEG2TS(
- DataSourceBase *source, String8 *mimeType, float *confidence,
- sp<AMessage> *);
+bool SniffMPEG2TS(DataSourceBase *source, float *confidence);
} // namespace android
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 1d04bed..6d7576f 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -27,7 +27,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferBase.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
@@ -54,7 +54,7 @@
virtual status_t stop();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
+ MediaBufferBase **buffer, const ReadOptions *options = NULL);
protected:
virtual ~OggSource();
@@ -82,7 +82,7 @@
status_t seekToTime(int64_t timeUs);
status_t seekToOffset(off64_t offset);
- virtual status_t readNextPacket(MediaBuffer **buffer) = 0;
+ virtual status_t readNextPacket(MediaBufferBase **buffer) = 0;
status_t init();
@@ -141,7 +141,7 @@
// 1 - bitstream identification header
// 3 - comment header
// 5 - codec setup header (Vorbis only)
- virtual status_t verifyHeader(MediaBuffer *buffer, uint8_t type) = 0;
+ virtual status_t verifyHeader(MediaBufferBase *buffer, uint8_t type) = 0;
// Read the next ogg packet from the underlying data source; optionally
// calculate the timestamp for the output packet whilst pretending
@@ -149,9 +149,9 @@
//
// *buffer is NULL'ed out immediately upon entry, and if successful a new buffer is allocated;
// clients are responsible for releasing the original buffer.
- status_t _readNextPacket(MediaBuffer **buffer, bool calcVorbisTimestamp);
+ status_t _readNextPacket(MediaBufferBase **buffer, bool calcVorbisTimestamp);
- int32_t getPacketBlockSize(MediaBuffer *buffer);
+ int32_t getPacketBlockSize(MediaBufferBase *buffer);
void parseFileMetaData();
@@ -173,7 +173,7 @@
virtual uint64_t approxBitrate() const;
- virtual status_t readNextPacket(MediaBuffer **buffer) {
+ virtual status_t readNextPacket(MediaBufferBase **buffer) {
return _readNextPacket(buffer, /* calcVorbisTimestamp = */ true);
}
@@ -185,7 +185,7 @@
return granulePos * 1000000ll / mVi.rate;
}
- virtual status_t verifyHeader(MediaBuffer *buffer, uint8_t type);
+ virtual status_t verifyHeader(MediaBufferBase *buffer, uint8_t type);
};
struct MyOpusExtractor : public MyOggExtractor {
@@ -203,16 +203,16 @@
return 0;
}
- virtual status_t readNextPacket(MediaBuffer **buffer);
+ virtual status_t readNextPacket(MediaBufferBase **buffer);
protected:
virtual int64_t getTimeUsOfGranule(uint64_t granulePos) const;
- virtual status_t verifyHeader(MediaBuffer *buffer, uint8_t type);
+ virtual status_t verifyHeader(MediaBufferBase *buffer, uint8_t type);
private:
- status_t verifyOpusHeader(MediaBuffer *buffer);
- status_t verifyOpusComments(MediaBuffer *buffer);
- uint32_t getNumSamplesInPacket(MediaBuffer *buffer) const;
+ status_t verifyOpusHeader(MediaBufferBase *buffer);
+ status_t verifyOpusComments(MediaBufferBase *buffer);
+ uint32_t getNumSamplesInPacket(MediaBufferBase *buffer) const;
uint8_t mChannelCount;
uint16_t mCodecDelay;
@@ -256,7 +256,7 @@
}
status_t OggSource::read(
- MediaBuffer **out, const ReadOptions *options) {
+ MediaBufferBase **out, const ReadOptions *options) {
*out = NULL;
int64_t seekTimeUs;
@@ -268,7 +268,7 @@
}
}
- MediaBuffer *packet;
+ MediaBufferBase *packet;
status_t err = mExtractor->mImpl->readNextPacket(&packet);
if (err != OK) {
@@ -562,13 +562,13 @@
return sizeof(header) + page->mNumSegments + totalSize;
}
-status_t MyOpusExtractor::readNextPacket(MediaBuffer **out) {
+status_t MyOpusExtractor::readNextPacket(MediaBufferBase **out) {
if (mOffset <= mFirstDataOffset && mStartGranulePosition < 0) {
// The first sample might not start at time 0; find out where by subtracting
// the number of samples on the first page from the granule position
// (position of last complete sample) of the first page. This happens
// the first time before we attempt to read a packet from the first page.
- MediaBuffer *mBuf;
+ MediaBufferBase *mBuf;
uint32_t numSamples = 0;
uint64_t curGranulePosition = 0;
while (true) {
@@ -623,7 +623,7 @@
return OK;
}
-uint32_t MyOpusExtractor::getNumSamplesInPacket(MediaBuffer *buffer) const {
+uint32_t MyOpusExtractor::getNumSamplesInPacket(MediaBufferBase *buffer) const {
if (buffer == NULL || buffer->range_length() < 1) {
return 0;
}
@@ -669,10 +669,10 @@
return numSamples;
}
-status_t MyOggExtractor::_readNextPacket(MediaBuffer **out, bool calcVorbisTimestamp) {
+status_t MyOggExtractor::_readNextPacket(MediaBufferBase **out, bool calcVorbisTimestamp) {
*out = NULL;
- MediaBuffer *buffer = NULL;
+ MediaBufferBase *buffer = NULL;
int64_t timeUs = -1;
for (;;) {
@@ -708,7 +708,7 @@
ALOGE("b/36592202");
return ERROR_MALFORMED;
}
- MediaBuffer *tmp = new (std::nothrow) MediaBuffer(fullSize);
+ MediaBufferBase *tmp = MediaBufferBase::Create(fullSize);
if (tmp == NULL) {
if (buffer != NULL) {
buffer->release();
@@ -833,7 +833,7 @@
mMeta->setCString(kKeyMIMEType, mMimeType);
status_t err;
- MediaBuffer *packet;
+ MediaBufferBase *packet;
for (size_t i = 0; i < mNumHeaders; ++i) {
// ignore timestamp for configuration packets
if ((err = _readNextPacket(&packet, /* calcVorbisTimestamp = */ false)) != OK) {
@@ -910,7 +910,7 @@
}
}
-int32_t MyOggExtractor::getPacketBlockSize(MediaBuffer *buffer) {
+int32_t MyOggExtractor::getPacketBlockSize(MediaBufferBase *buffer) {
const uint8_t *data =
(const uint8_t *)buffer->data() + buffer->range_offset();
@@ -950,7 +950,7 @@
return pcmSamplePosition * 1000000ll / kOpusSampleRate;
}
-status_t MyOpusExtractor::verifyHeader(MediaBuffer *buffer, uint8_t type) {
+status_t MyOpusExtractor::verifyHeader(MediaBufferBase *buffer, uint8_t type) {
switch (type) {
// there are actually no header types defined in the Opus spec; we choose 1 and 3 to mean
// header and comments such that we can share code with MyVorbisExtractor.
@@ -963,7 +963,7 @@
}
}
-status_t MyOpusExtractor::verifyOpusHeader(MediaBuffer *buffer) {
+status_t MyOpusExtractor::verifyOpusHeader(MediaBufferBase *buffer) {
const size_t kOpusHeaderSize = 19;
const uint8_t *data =
(const uint8_t *)buffer->data() + buffer->range_offset();
@@ -989,7 +989,7 @@
return OK;
}
-status_t MyOpusExtractor::verifyOpusComments(MediaBuffer *buffer) {
+status_t MyOpusExtractor::verifyOpusComments(MediaBufferBase *buffer) {
// add artificial framing bit so we can reuse _vorbis_unpack_comment
int32_t commentSize = buffer->range_length() + 1;
sp<ABuffer> aBuf = new ABuffer(commentSize);
@@ -1081,7 +1081,7 @@
}
status_t MyVorbisExtractor::verifyHeader(
- MediaBuffer *buffer, uint8_t type) {
+ MediaBufferBase *buffer, uint8_t type) {
const uint8_t *data =
(const uint8_t *)buffer->data() + buffer->range_offset();
@@ -1371,21 +1371,20 @@
static MediaExtractor* CreateExtractor(
DataSourceBase *source,
- const sp<AMessage>& meta __unused) {
+ void *) {
return new OggExtractor(source);
}
static MediaExtractor::CreatorFunc Sniff(
DataSourceBase *source,
- String8 *mimeType,
float *confidence,
- sp<AMessage> *) {
+ void **,
+ MediaExtractor::FreeMetaFunc *) {
char tmp[4];
if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) {
return NULL;
}
- mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_OGG);
*confidence = 0.2f;
return CreateExtractor;
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index 105a37f..a18cee5 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -68,7 +68,7 @@
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
+ MediaBufferBase **buffer, const ReadOptions *options = NULL);
virtual bool supportNonblockingRead() { return true; }
@@ -385,7 +385,7 @@
if (mBitsPerSample == 8) {
// As a temporary buffer for 8->16 bit conversion.
- mGroup->add_buffer(new MediaBuffer(kMaxFrameSize));
+ mGroup->add_buffer(MediaBufferBase::Create(kMaxFrameSize));
}
mCurrentPos = mOffset;
@@ -415,7 +415,7 @@
}
status_t WAVSource::read(
- MediaBuffer **out, const ReadOptions *options) {
+ MediaBufferBase **out, const ReadOptions *options) {
*out = NULL;
if (options != nullptr && options->getNonBlocking() && !mGroup->has_buffers()) {
@@ -441,7 +441,7 @@
mCurrentPos = pos + mOffset;
}
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
status_t err = mGroup->acquire_buffer(&buffer);
if (err != OK) {
return err;
@@ -492,7 +492,7 @@
// Convert 8-bit unsigned samples to 16-bit signed.
// Create new buffer with 2 byte wide samples
- MediaBuffer *tmp;
+ MediaBufferBase *tmp;
CHECK_EQ(mGroup->acquire_buffer(&tmp), (status_t)OK);
tmp->set_range(0, 2 * n);
@@ -546,15 +546,15 @@
static MediaExtractor* CreateExtractor(
DataSourceBase *source,
- const sp<AMessage>& meta __unused) {
+ void *) {
return new WAVExtractor(source);
}
static MediaExtractor::CreatorFunc Sniff(
DataSourceBase *source,
- String8 *mimeType,
float *confidence,
- sp<AMessage> *) {
+ void **,
+ MediaExtractor::FreeMetaFunc *) {
char header[12];
if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
return NULL;
@@ -571,7 +571,6 @@
return NULL;
}
- *mimeType = MEDIA_MIMETYPE_CONTAINER_WAV;
*confidence = 0.3f;
return CreateExtractor;
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index 51ccb5a..e9a6230 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -35,9 +35,7 @@
GETTRACKMETADATA,
GETMETADATA,
FLAGS,
- GETDRMTRACKINFO,
SETMEDIACAS,
- SETUID,
NAME,
GETMETRICS
};
@@ -112,11 +110,6 @@
return 0;
}
- virtual char* getDrmTrackInfo(size_t trackID __unused, int *len __unused) {
- ALOGV("getDrmTrackInfo NOT IMPLEMENTED");
- return NULL;
- }
-
virtual status_t setMediaCas(const HInterfaceToken &casToken) {
ALOGV("setMediaCas");
@@ -131,10 +124,6 @@
return reply.readInt32();
}
- virtual void setUID(uid_t uid __unused) {
- ALOGV("setUID NOT IMPLEMENTED");
- }
-
virtual const char * name() {
ALOGV("name NOT IMPLEMENTED");
return NULL;
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index 0d5127c..f6b9255 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -113,9 +113,9 @@
return NULL;
}
- virtual status_t read(MediaBuffer **buffer,
+ virtual status_t read(MediaBufferBase **buffer,
const MediaSource::ReadOptions *options) {
- Vector<MediaBuffer *> buffers;
+ Vector<MediaBufferBase *> buffers;
status_t ret = readMultiple(&buffers, 1 /* maxNumBuffers */, options);
*buffer = buffers.size() == 0 ? nullptr : buffers[0];
ALOGV("read status %d, bufferCount %u, sinceStop %u",
@@ -124,7 +124,7 @@
}
virtual status_t readMultiple(
- Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers,
+ Vector<MediaBufferBase *> *buffers, uint32_t maxNumBuffers,
const MediaSource::ReadOptions *options) {
ALOGV("readMultiple");
if (buffers == NULL || !buffers->isEmpty()) {
@@ -341,7 +341,7 @@
uint32_t bufferCount = 0;
for (; bufferCount < maxNumBuffers; ++bufferCount, ++mBuffersSinceStop) {
MediaBuffer *buf = nullptr;
- ret = read(&buf, useOptions ? &opts : nullptr);
+ ret = read((MediaBufferBase **)&buf, useOptions ? &opts : nullptr);
opts.clearNonPersistent(); // Remove options that only apply to first buffer.
if (ret != NO_ERROR || buf == nullptr) {
break;
@@ -364,7 +364,7 @@
} else {
ALOGD("Large buffer %zu without IMemory!", length);
ret = mGroup->acquire_buffer(
- &transferBuf, false /* nonBlocking */, length);
+ (MediaBufferBase **)&transferBuf, false /* nonBlocking */, length);
if (ret != OK
|| transferBuf == nullptr
|| transferBuf->mMemory == nullptr) {
diff --git a/media/libmedia/MidiIoWrapper.cpp b/media/libmedia/MidiIoWrapper.cpp
index 0896e75..5ca3b48 100644
--- a/media/libmedia/MidiIoWrapper.cpp
+++ b/media/libmedia/MidiIoWrapper.cpp
@@ -38,6 +38,7 @@
mFd = open(path, O_RDONLY | O_LARGEFILE);
mBase = 0;
mLength = lseek(mFd, 0, SEEK_END);
+ mDataSource = nullptr;
}
MidiIoWrapper::MidiIoWrapper(int fd, off64_t offset, int64_t size) {
@@ -45,6 +46,7 @@
mFd = fd < 0 ? -1 : dup(fd);
mBase = offset;
mLength = size;
+ mDataSource = nullptr;
}
MidiIoWrapper::MidiIoWrapper(DataSourceBase *source) {
diff --git a/media/libmedia/NdkWrapper.cpp b/media/libmedia/NdkWrapper.cpp
index 942393d..936e92f 100644
--- a/media/libmedia/NdkWrapper.cpp
+++ b/media/libmedia/NdkWrapper.cpp
@@ -1057,6 +1057,13 @@
return translateErrorCode(AMediaExtractor_setDataSource(mAMediaExtractor, location));
}
+status_t AMediaExtractorWrapper::setDataSource(AMediaDataSource *source) {
+ if (mAMediaExtractor == NULL) {
+ return DEAD_OBJECT;
+ }
+ return translateErrorCode(AMediaExtractor_setDataSourceCustom(mAMediaExtractor, source));
+}
+
size_t AMediaExtractorWrapper::getTrackCount() {
if (mAMediaExtractor == NULL) {
return 0;
@@ -1064,6 +1071,13 @@
return AMediaExtractor_getTrackCount(mAMediaExtractor);
}
+sp<AMediaFormatWrapper> AMediaExtractorWrapper::getFormat() {
+ if (mAMediaExtractor == NULL) {
+ return NULL;
+ }
+ return new AMediaFormatWrapper(AMediaExtractor_getFileFormat(mAMediaExtractor));
+}
+
sp<AMediaFormatWrapper> AMediaExtractorWrapper::getTrackFormat(size_t idx) {
if (mAMediaExtractor == NULL) {
return NULL;
@@ -1085,6 +1099,26 @@
return translateErrorCode(AMediaExtractor_unselectTrack(mAMediaExtractor, idx));
}
+status_t AMediaExtractorWrapper::selectSingleTrack(size_t idx) {
+ if (mAMediaExtractor == NULL) {
+ return DEAD_OBJECT;
+ }
+ for (size_t i = 0; i < AMediaExtractor_getTrackCount(mAMediaExtractor); ++i) {
+ if (i == idx) {
+ media_status_t err = AMediaExtractor_selectTrack(mAMediaExtractor, i);
+ if (err != AMEDIA_OK) {
+ return translateErrorCode(err);
+ }
+ } else {
+ media_status_t err = AMediaExtractor_unselectTrack(mAMediaExtractor, i);
+ if (err != AMEDIA_OK) {
+ return translateErrorCode(err);
+ }
+ }
+ }
+ return OK;
+}
+
ssize_t AMediaExtractorWrapper::readSampleData(const sp<ABuffer> &buffer) {
if (mAMediaExtractor == NULL) {
return -1;
@@ -1092,6 +1126,13 @@
return AMediaExtractor_readSampleData(mAMediaExtractor, buffer->data(), buffer->capacity());
}
+ssize_t AMediaExtractorWrapper::getSampleSize() {
+ if (mAMediaExtractor == NULL) {
+ return 0;
+ }
+ return AMediaExtractor_getSampleSize(mAMediaExtractor);
+}
+
uint32_t AMediaExtractorWrapper::getSampleFlags() {
if (mAMediaExtractor == NULL) {
return 0;
@@ -1113,6 +1154,13 @@
return AMediaExtractor_getSampleTime(mAMediaExtractor);
}
+int64_t AMediaExtractorWrapper::getCachedDuration() {
+ if (mAMediaExtractor == NULL) {
+ return -1;
+ }
+ return AMediaExtractor_getCachedDuration(mAMediaExtractor);
+}
+
bool AMediaExtractorWrapper::advance() {
if (mAMediaExtractor == NULL) {
return false;
@@ -1120,11 +1168,27 @@
return AMediaExtractor_advance(mAMediaExtractor);
}
-status_t AMediaExtractorWrapper::seekTo(int64_t seekPosUs, SeekMode mode) {
+status_t AMediaExtractorWrapper::seekTo(int64_t seekPosUs, MediaSource::ReadOptions::SeekMode mode) {
if (mAMediaExtractor == NULL) {
return DEAD_OBJECT;
}
- return AMediaExtractor_seekTo(mAMediaExtractor, seekPosUs, mode);
+
+ SeekMode aMode;
+ switch (mode) {
+ case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC: {
+ aMode = AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC;
+ break;
+ }
+ case MediaSource::ReadOptions::SEEK_NEXT_SYNC: {
+ aMode = AMEDIAEXTRACTOR_SEEK_NEXT_SYNC;
+ break;
+ }
+ default: {
+ aMode = AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC;
+ break;
+ }
+ }
+ return AMediaExtractor_seekTo(mAMediaExtractor, seekPosUs, aMode);
}
PsshInfo* AMediaExtractorWrapper::getPsshInfo() {
@@ -1141,4 +1205,43 @@
return new AMediaCodecCryptoInfoWrapper(AMediaExtractor_getSampleCryptoInfo(mAMediaExtractor));
}
+ssize_t AMediaDataSourceWrapper::AMediaDataSourceWrapper_getSize(void *userdata) {
+ DataSource *source = static_cast<DataSource *>(userdata);
+ off64_t size = -1;
+ source->getSize(&size);
+ return size;
+}
+
+ssize_t AMediaDataSourceWrapper::AMediaDataSourceWrapper_readAt(void *userdata, off64_t offset, void * buf, size_t size) {
+ DataSource *source = static_cast<DataSource *>(userdata);
+ return source->readAt(offset, buf, size);
+}
+
+void AMediaDataSourceWrapper::AMediaDataSourceWrapper_close(void *userdata) {
+ DataSource *source = static_cast<DataSource *>(userdata);
+ source->close();
+}
+
+AMediaDataSourceWrapper::AMediaDataSourceWrapper(const sp<DataSource> &dataSource)
+ : mDataSource(dataSource),
+ mAMediaDataSource(AMediaDataSource_new()) {
+ ALOGV("setDataSource (source: %p)", dataSource.get());
+ AMediaDataSource_setUserdata(mAMediaDataSource, dataSource.get());
+ AMediaDataSource_setReadAt(mAMediaDataSource, AMediaDataSourceWrapper_readAt);
+ AMediaDataSource_setGetSize(mAMediaDataSource, AMediaDataSourceWrapper_getSize);
+ AMediaDataSource_setClose(mAMediaDataSource, AMediaDataSourceWrapper_close);
+}
+
+AMediaDataSourceWrapper::~AMediaDataSourceWrapper() {
+ if (mAMediaDataSource == NULL) {
+ return;
+ }
+ AMediaDataSource_delete(mAMediaDataSource);
+ mAMediaDataSource = NULL;
+}
+
+AMediaDataSource* AMediaDataSourceWrapper::getAMediaDataSource() {
+ return mAMediaDataSource;
+}
+
} // namespace android
diff --git a/media/libmedia/include/media/DrmHal.h b/media/libmedia/include/media/DrmHal.h
index 1c09036..bf91ea9 100644
--- a/media/libmedia/include/media/DrmHal.h
+++ b/media/libmedia/include/media/DrmHal.h
@@ -119,7 +119,7 @@
virtual status_t setPropertyString(String8 const &name, String8 const &value ) const;
virtual status_t setPropertyByteArray(String8 const &name,
Vector<uint8_t> const &value ) const;
- virtual status_t getMetrics(MediaAnalyticsItem *item);
+ virtual status_t getMetrics(os::PersistableBundle *metrics);
virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
String8 const &algorithm);
@@ -203,7 +203,8 @@
void writeByteArray(Parcel &obj, const hidl_vec<uint8_t>& array);
- void reportMetrics() const;
+ void reportPluginMetrics() const;
+ void reportFrameworkMetrics() const;
status_t getPropertyStringInternal(String8 const &name, String8 &value) const;
status_t getPropertyByteArrayInternal(String8 const &name,
Vector<uint8_t> &value) const;
diff --git a/media/libmedia/include/media/DrmMetrics.h b/media/libmedia/include/media/DrmMetrics.h
index bb7509b..5c2fdf2 100644
--- a/media/libmedia/include/media/DrmMetrics.h
+++ b/media/libmedia/include/media/DrmMetrics.h
@@ -20,6 +20,7 @@
#include <map>
#include <android/hardware/drm/1.0/types.h>
+#include <binder/PersistableBundle.h>
#include <media/CounterMetric.h>
#include <media/EventMetric.h>
@@ -28,19 +29,20 @@
/**
* This class contains the definition of metrics captured within MediaDrm.
* It also contains a method for exporting all of the metrics to a
- * MediaAnalyticsItem instance.
+ * PersistableBundle.
*/
class MediaDrmMetrics {
public:
explicit MediaDrmMetrics();
+ virtual ~MediaDrmMetrics() {};
// Count of openSession calls.
CounterMetric<status_t> mOpenSessionCounter;
// Count of closeSession calls.
CounterMetric<status_t> mCloseSessionCounter;
// Count and timing of getKeyRequest calls.
- EventMetric<status_t> mGetKeyRequestTiming;
+ EventMetric<status_t> mGetKeyRequestTimeUs;
// Count and timing of provideKeyResponse calls.
- EventMetric<status_t> mProvideKeyResponseTiming;
+ EventMetric<status_t> mProvideKeyResponseTimeUs;
// Count of getProvisionRequest calls.
CounterMetric<status_t> mGetProvisionRequestCounter;
// Count of provideProvisionResponse calls.
@@ -55,10 +57,37 @@
// Count getPropertyByteArray calls to retrieve the device unique id.
CounterMetric<status_t> mGetDeviceUniqueIdCounter;
- // TODO: Add session start and end time support. These are a special case.
+ // Adds a session start time record.
+ void SetSessionStart(const Vector<uint8_t>& sessionId);
- // Export the metrics to a MediaAnalyticsItem.
- void Export(MediaAnalyticsItem* item);
+ // Adds a session end time record.
+ void SetSessionEnd(const Vector<uint8_t>& sessionId);
+
+ // The app package name is the application package name that is using the
+ // instance. The app package name is held here for convenience. It is not
+ // serialized or exported with the metrics.
+ void SetAppPackageName(const String8& appPackageName) { mAppPackageName = appPackageName; }
+ const String8& GetAppPackageName() { return mAppPackageName; }
+
+ // Export the metrics to a PersistableBundle.
+ void Export(os::PersistableBundle* metricsBundle);
+
+ // Get the serialized metrics. Metrics are formatted as a serialized
+ // DrmFrameworkMetrics proto. If there is a failure serializing the metrics,
+ // this returns an error. The parameter |serlializedMetrics| is owned by the
+ // caller and must not be null.
+ status_t GetSerializedMetrics(std::string* serializedMetrics);
+
+ protected:
+ // This is visible for testing only.
+ virtual int64_t GetCurrentTimeMs();
+
+ private:
+ // Session lifetimes. A pair of values representing the milliseconds since
+ // epoch, UTC. The first value is the start time, the second is the end time.
+ std::map<std::string, std::pair<int64_t, int64_t>> mSessionLifespans;
+
+ String8 mAppPackageName;
};
} // namespace android
diff --git a/media/libmedia/include/media/IDrm.h b/media/libmedia/include/media/IDrm.h
index c3ae684..a19b06b 100644
--- a/media/libmedia/include/media/IDrm.h
+++ b/media/libmedia/include/media/IDrm.h
@@ -15,6 +15,7 @@
*/
#include <binder/IInterface.h>
+#include <binder/PersistableBundle.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/drm/DrmAPI.h>
#include <media/IDrmClient.h>
@@ -98,7 +99,7 @@
virtual status_t setPropertyByteArray(String8 const &name,
Vector<uint8_t> const &value) const = 0;
- virtual status_t getMetrics(MediaAnalyticsItem *item) = 0;
+ virtual status_t getMetrics(os::PersistableBundle *metrics) = 0;
virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
String8 const &algorithm) = 0;
diff --git a/media/libmedia/include/media/IMediaExtractor.h b/media/libmedia/include/media/IMediaExtractor.h
index 9899429..75e4ee2 100644
--- a/media/libmedia/include/media/IMediaExtractor.h
+++ b/media/libmedia/include/media/IMediaExtractor.h
@@ -60,13 +60,8 @@
// CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
virtual uint32_t flags() const = 0;
- // for DRM
- virtual char* getDrmTrackInfo(size_t trackID, int *len) = 0;
-
virtual status_t setMediaCas(const HInterfaceToken &casToken) = 0;
- virtual void setUID(uid_t uid) = 0;
-
virtual const char * name() = 0;
};
diff --git a/media/libmedia/include/media/IMediaSource.h b/media/libmedia/include/media/IMediaSource.h
index dabe231..7a4b1b9 100644
--- a/media/libmedia/include/media/IMediaSource.h
+++ b/media/libmedia/include/media/IMediaSource.h
@@ -64,7 +64,7 @@
//
// TODO: consider removing read() in favor of readMultiple().
virtual status_t read(
- MediaBuffer **buffer,
+ MediaBufferBase **buffer,
const MediaSource::ReadOptions *options = NULL) = 0;
// Returns a vector of new buffers of data, where the new buffers are added
@@ -80,7 +80,7 @@
// ReadOptions may be specified. Persistent options apply to all reads;
// non-persistent options (e.g. seek) apply only to the first read.
virtual status_t readMultiple(
- Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers = 1,
+ Vector<MediaBufferBase *> *buffers, uint32_t maxNumBuffers = 1,
const MediaSource::ReadOptions *options = nullptr) = 0;
// Returns true if |readMultiple| is supported, otherwise false.
@@ -110,7 +110,7 @@
// TODO: Implement this for local media sources.
virtual status_t readMultiple(
- Vector<MediaBuffer *> * /* buffers */, uint32_t /* maxNumBuffers = 1 */,
+ Vector<MediaBufferBase *> * /* buffers */, uint32_t /* maxNumBuffers = 1 */,
const MediaSource::ReadOptions * /* options = nullptr */) {
return ERROR_UNSUPPORTED;
}
diff --git a/media/libmedia/include/media/MediaBufferHolder.h b/media/libmedia/include/media/MediaBufferHolder.h
index e8e2c4b..f9dfdf5 100644
--- a/media/libmedia/include/media/MediaBufferHolder.h
+++ b/media/libmedia/include/media/MediaBufferHolder.h
@@ -24,7 +24,7 @@
namespace android {
struct MediaBufferHolder : public RefBase {
- MediaBufferHolder(MediaBuffer* buffer)
+ MediaBufferHolder(MediaBufferBase* buffer)
: mMediaBuffer(buffer) {
if (mMediaBuffer != nullptr) {
mMediaBuffer->add_ref();
@@ -37,10 +37,10 @@
}
}
- MediaBuffer* mediaBuffer() { return mMediaBuffer; }
+ MediaBufferBase* mediaBuffer() { return mMediaBuffer; }
private:
- MediaBuffer* const mMediaBuffer;
+ MediaBufferBase* const mMediaBuffer;
};
} // android
diff --git a/media/libmedia/include/media/NdkWrapper.h b/media/libmedia/include/media/NdkWrapper.h
index 00e0fd4..49d728d 100644
--- a/media/libmedia/include/media/NdkWrapper.h
+++ b/media/libmedia/include/media/NdkWrapper.h
@@ -18,6 +18,9 @@
#define NDK_WRAPPER_H_
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
+#include <media/NdkMediaDataSource.h>
#include <media/NdkMediaError.h>
#include <media/NdkMediaExtractor.h>
#include <media/hardware/CryptoAPI.h>
@@ -286,25 +289,35 @@
status_t setDataSource(const char *location);
+ status_t setDataSource(AMediaDataSource *);
+
size_t getTrackCount();
+ sp<AMediaFormatWrapper> getFormat();
+
sp<AMediaFormatWrapper> getTrackFormat(size_t idx);
status_t selectTrack(size_t idx);
status_t unselectTrack(size_t idx);
+ status_t selectSingleTrack(size_t idx);
+
ssize_t readSampleData(const sp<ABuffer> &buffer);
+ ssize_t getSampleSize();
+
uint32_t getSampleFlags();
int getSampleTrackIndex();
int64_t getSampleTime();
+ int64_t getCachedDuration();
+
bool advance();
- status_t seekTo(int64_t seekPosUs, SeekMode mode);
+ status_t seekTo(int64_t seekPosUs, MediaSource::ReadOptions::SeekMode mode);
// the returned PsshInfo is still owned by this wrapper.
PsshInfo* getPsshInfo();
@@ -320,6 +333,31 @@
DISALLOW_EVIL_CONSTRUCTORS(AMediaExtractorWrapper);
};
+struct AMediaDataSourceWrapper : public RefBase {
+
+ static status_t translate_error(media_status_t err);
+
+ static ssize_t AMediaDataSourceWrapper_getSize(void *userdata);
+
+ static ssize_t AMediaDataSourceWrapper_readAt(void *userdata, off64_t offset, void * buf, size_t size);
+
+ static void AMediaDataSourceWrapper_close(void *userdata);
+
+ AMediaDataSourceWrapper(const sp<DataSource> &dataSource);
+
+ AMediaDataSource *getAMediaDataSource();
+
+protected:
+ virtual ~AMediaDataSourceWrapper();
+
+private:
+ sp<DataSource> mDataSource;
+
+ AMediaDataSource *mAMediaDataSource;
+
+ DISALLOW_EVIL_CONSTRUCTORS(AMediaDataSourceWrapper);
+};
+
} // namespace android
#endif // NDK_WRAPPER_H_
diff --git a/media/libmedia/include/media/OMXBuffer.h b/media/libmedia/include/media/OMXBuffer.h
index 3e84858..9c9f5e7 100644
--- a/media/libmedia/include/media/OMXBuffer.h
+++ b/media/libmedia/include/media/OMXBuffer.h
@@ -91,6 +91,7 @@
private:
friend struct OMXNodeInstance;
+ friend struct C2OMXNode;
// This is needed temporarily for OMX HIDL transition.
friend inline bool (::android::hardware::media::omx::V1_0::implementation::
diff --git a/media/libmediaextractor/Android.bp b/media/libmediaextractor/Android.bp
index 8f4ba70..79af058 100644
--- a/media/libmediaextractor/Android.bp
+++ b/media/libmediaextractor/Android.bp
@@ -25,6 +25,7 @@
srcs: [
"DataSourceBase.cpp",
"MediaBuffer.cpp",
+ "MediaBufferBase.cpp",
"MediaBufferGroup.cpp",
"MediaSourceBase.cpp",
"MediaSource.cpp",
diff --git a/media/libmediaextractor/MediaBuffer.cpp b/media/libmediaextractor/MediaBuffer.cpp
index 28fc760..dac3d50 100644
--- a/media/libmediaextractor/MediaBuffer.cpp
+++ b/media/libmediaextractor/MediaBuffer.cpp
@@ -177,7 +177,7 @@
mObserver = observer;
}
-MediaBuffer *MediaBuffer::clone() {
+MediaBufferBase *MediaBuffer::clone() {
MediaBuffer *buffer = new MediaBuffer(mData, mSize);
buffer->set_range(mRangeOffset, mRangeLength);
buffer->mMetaData = new MetaData(*mMetaData.get());
diff --git a/media/libmediaextractor/MediaBufferBase.cpp b/media/libmediaextractor/MediaBufferBase.cpp
new file mode 100644
index 0000000..a553289
--- /dev/null
+++ b/media/libmediaextractor/MediaBufferBase.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright 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_TAG "MediaBufferBase"
+#include <utils/Log.h>
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferBase.h>
+
+namespace android {
+
+//static
+MediaBufferBase *MediaBufferBase::Create(size_t size) {
+ return new (std::nothrow) MediaBuffer(size);
+}
+
+} // android
diff --git a/media/libmediaextractor/MediaBufferGroup.cpp b/media/libmediaextractor/MediaBufferGroup.cpp
index cb62d92..2a8dd41 100644
--- a/media/libmediaextractor/MediaBufferGroup.cpp
+++ b/media/libmediaextractor/MediaBufferGroup.cpp
@@ -17,9 +17,13 @@
#define LOG_TAG "MediaBufferGroup"
#include <utils/Log.h>
+#include <list>
+
+#include <binder/MemoryDealer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
+#include <utils/threads.h>
namespace android {
@@ -32,17 +36,26 @@
static const size_t kSharedMemoryThreshold = MIN(
(size_t)MediaBuffer::kSharedMemThreshold, (size_t)(4 * 1024));
-MediaBufferGroup::MediaBufferGroup(size_t growthLimit) :
- mGrowthLimit(growthLimit) {
+struct MediaBufferGroup::InternalData {
+ Mutex mLock;
+ Condition mCondition;
+ size_t mGrowthLimit; // Do not automatically grow group larger than this.
+ std::list<MediaBufferBase *> mBuffers;
+};
+
+MediaBufferGroup::MediaBufferGroup(size_t growthLimit)
+ : mInternal(new InternalData()) {
+ mInternal->mGrowthLimit = growthLimit;
}
MediaBufferGroup::MediaBufferGroup(size_t buffers, size_t buffer_size, size_t growthLimit)
- : mGrowthLimit(growthLimit) {
+ : mInternal(new InternalData()) {
+ mInternal->mGrowthLimit = growthLimit;
- if (mGrowthLimit > 0 && buffers > mGrowthLimit) {
+ if (mInternal->mGrowthLimit > 0 && buffers > mInternal->mGrowthLimit) {
ALOGW("Preallocated buffers %zu > growthLimit %zu, increasing growthLimit",
- buffers, mGrowthLimit);
- mGrowthLimit = buffers;
+ buffers, mInternal->mGrowthLimit);
+ mInternal->mGrowthLimit = buffers;
}
if (buffer_size >= kSharedMemoryThreshold) {
@@ -81,7 +94,7 @@
}
MediaBufferGroup::~MediaBufferGroup() {
- for (MediaBuffer *buffer : mBuffers) {
+ for (MediaBufferBase *buffer : mInternal->mBuffers) {
if (buffer->refcount() != 0) {
const int localRefcount = buffer->localRefcount();
const int remoteRefcount = buffer->remoteRefcount();
@@ -103,34 +116,35 @@
buffer->setObserver(nullptr);
buffer->release();
}
+ delete mInternal;
}
-void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
- Mutex::Autolock autoLock(mLock);
+void MediaBufferGroup::add_buffer(MediaBufferBase *buffer) {
+ Mutex::Autolock autoLock(mInternal->mLock);
// if we're above our growth limit, release buffers if we can
- for (auto it = mBuffers.begin();
- mGrowthLimit > 0
- && mBuffers.size() >= mGrowthLimit
- && it != mBuffers.end();) {
+ for (auto it = mInternal->mBuffers.begin();
+ mInternal->mGrowthLimit > 0
+ && mInternal->mBuffers.size() >= mInternal->mGrowthLimit
+ && it != mInternal->mBuffers.end();) {
if ((*it)->refcount() == 0) {
(*it)->setObserver(nullptr);
(*it)->release();
- it = mBuffers.erase(it);
+ it = mInternal->mBuffers.erase(it);
} else {
++it;
}
}
buffer->setObserver(this);
- mBuffers.emplace_back(buffer);
+ mInternal->mBuffers.emplace_back(buffer);
}
bool MediaBufferGroup::has_buffers() {
- if (mBuffers.size() < mGrowthLimit) {
+ if (mInternal->mBuffers.size() < mInternal->mGrowthLimit) {
return true; // We can add more buffers internally.
}
- for (MediaBuffer *buffer : mBuffers) {
+ for (MediaBufferBase *buffer : mInternal->mBuffers) {
if (buffer->refcount() == 0) {
return true;
}
@@ -139,13 +153,13 @@
}
status_t MediaBufferGroup::acquire_buffer(
- MediaBuffer **out, bool nonBlocking, size_t requestedSize) {
- Mutex::Autolock autoLock(mLock);
+ MediaBufferBase **out, bool nonBlocking, size_t requestedSize) {
+ Mutex::Autolock autoLock(mInternal->mLock);
for (;;) {
size_t smallest = requestedSize;
- MediaBuffer *buffer = nullptr;
- auto free = mBuffers.end();
- for (auto it = mBuffers.begin(); it != mBuffers.end(); ++it) {
+ MediaBufferBase *buffer = nullptr;
+ auto free = mInternal->mBuffers.end();
+ for (auto it = mInternal->mBuffers.begin(); it != mInternal->mBuffers.end(); ++it) {
if ((*it)->refcount() == 0) {
const size_t size = (*it)->size();
if (size >= requestedSize) {
@@ -159,7 +173,8 @@
}
}
if (buffer == nullptr
- && (free != mBuffers.end() || mBuffers.size() < mGrowthLimit)) {
+ && (free != mInternal->mBuffers.end()
+ || mInternal->mBuffers.size() < mInternal->mGrowthLimit)) {
// We alloc before we free so failure leaves group unchanged.
const size_t allocateSize = requestedSize < SIZE_MAX / 3 * 2 /* NB: ordering */ ?
requestedSize * 3 / 2 : requestedSize;
@@ -170,7 +185,7 @@
buffer = nullptr;
} else {
buffer->setObserver(this);
- if (free != mBuffers.end()) {
+ if (free != mInternal->mBuffers.end()) {
ALOGV("reallocate buffer, requested size %zu vs available %zu",
requestedSize, (*free)->size());
(*free)->setObserver(nullptr);
@@ -178,7 +193,7 @@
*free = buffer; // in-place replace
} else {
ALOGV("allocate buffer, requested size %zu", requestedSize);
- mBuffers.emplace_back(buffer);
+ mInternal->mBuffers.emplace_back(buffer);
}
}
}
@@ -193,14 +208,18 @@
return WOULD_BLOCK;
}
// All buffers are in use, block until one of them is returned.
- mCondition.wait(mLock);
+ mInternal->mCondition.wait(mInternal->mLock);
}
// Never gets here.
}
-void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
- Mutex::Autolock autoLock(mLock);
- mCondition.signal();
+size_t MediaBufferGroup::buffers() const {
+ return mInternal->mBuffers.size();
+}
+
+void MediaBufferGroup::signalBufferReturned(MediaBufferBase *) {
+ Mutex::Autolock autoLock(mInternal->mLock);
+ mInternal->mCondition.signal();
}
} // namespace android
diff --git a/media/libmediaextractor/MetaData.cpp b/media/libmediaextractor/MetaData.cpp
index 98cddbe..69beea1 100644
--- a/media/libmediaextractor/MetaData.cpp
+++ b/media/libmediaextractor/MetaData.cpp
@@ -146,7 +146,7 @@
/**
* Note that the returned pointer becomes invalid when additional metadata is set.
*/
-bool MetaData::findCString(uint32_t key, const char **value) {
+bool MetaData::findCString(uint32_t key, const char **value) const {
uint32_t type;
const void *data;
size_t size;
@@ -159,7 +159,7 @@
return true;
}
-bool MetaData::findInt32(uint32_t key, int32_t *value) {
+bool MetaData::findInt32(uint32_t key, int32_t *value) const {
uint32_t type = 0;
const void *data;
size_t size;
@@ -174,7 +174,7 @@
return true;
}
-bool MetaData::findInt64(uint32_t key, int64_t *value) {
+bool MetaData::findInt64(uint32_t key, int64_t *value) const {
uint32_t type = 0;
const void *data;
size_t size;
@@ -189,7 +189,7 @@
return true;
}
-bool MetaData::findFloat(uint32_t key, float *value) {
+bool MetaData::findFloat(uint32_t key, float *value) const {
uint32_t type = 0;
const void *data;
size_t size;
@@ -204,7 +204,7 @@
return true;
}
-bool MetaData::findPointer(uint32_t key, void **value) {
+bool MetaData::findPointer(uint32_t key, void **value) const {
uint32_t type = 0;
const void *data;
size_t size;
@@ -222,7 +222,7 @@
bool MetaData::findRect(
uint32_t key,
int32_t *left, int32_t *top,
- int32_t *right, int32_t *bottom) {
+ int32_t *right, int32_t *bottom) const {
uint32_t type = 0;
const void *data;
size_t size;
diff --git a/media/libmediaextractor/include/media/DataSourceBase.h b/media/libmediaextractor/include/media/DataSourceBase.h
index f964137..8028dd7 100644
--- a/media/libmediaextractor/include/media/DataSourceBase.h
+++ b/media/libmediaextractor/include/media/DataSourceBase.h
@@ -58,20 +58,6 @@
bool getUInt32Var(off64_t offset, uint32_t *x, size_t size);
bool getUInt64Var(off64_t offset, uint64_t *x, size_t size);
- // Reads in "count" entries of type T into vector *x.
- // Returns true if "count" entries can be read.
- // If fewer than "count" entries can be read, return false. In this case,
- // the output vector *x will still have those entries that were read. Call
- // x->size() to obtain the number of entries read.
- // The optional parameter chunkSize specifies how many entries should be
- // read from the data source at one time into a temporary buffer. Increasing
- // chunkSize can improve the performance at the cost of extra memory usage.
- // The default value for chunkSize is set to read at least 4k bytes at a
- // time, depending on sizeof(T).
- template <typename T>
- bool getVector(off64_t offset, Vector<T>* x, size_t count,
- size_t chunkSize = (4095 / sizeof(T)) + 1);
-
// May return ERROR_UNSUPPORTED.
virtual status_t getSize(off64_t *size);
@@ -110,51 +96,6 @@
DataSourceBase &operator=(const DataSourceBase &);
};
-template <typename T>
-bool DataSourceBase::getVector(off64_t offset, Vector<T>* x, size_t count,
- size_t chunkSize)
-{
- x->clear();
- if (chunkSize == 0) {
- return false;
- }
- if (count == 0) {
- return true;
- }
-
- T tmp[chunkSize];
- ssize_t numBytesRead;
- size_t numBytesPerChunk = chunkSize * sizeof(T);
- size_t i;
-
- for (i = 0; i + chunkSize < count; i += chunkSize) {
- // This loops is executed when more than chunkSize records need to be
- // read.
- numBytesRead = this->readAt(offset, (void*)&tmp, numBytesPerChunk);
- if (numBytesRead == -1) { // If readAt() returns -1, there is an error.
- return false;
- }
- if (static_cast<size_t>(numBytesRead) < numBytesPerChunk) {
- // This case is triggered when the stream ends before the whole
- // chunk is read.
- x->appendArray(tmp, (size_t)numBytesRead / sizeof(T));
- return false;
- }
- x->appendArray(tmp, chunkSize);
- offset += numBytesPerChunk;
- }
-
- // There are (count - i) more records to read.
- // Right now, (count - i) <= chunkSize.
- // We do the same thing as above, but with chunkSize replaced by count - i.
- numBytesRead = this->readAt(offset, (void*)&tmp, (count - i) * sizeof(T));
- if (numBytesRead == -1) {
- return false;
- }
- x->appendArray(tmp, (size_t)numBytesRead / sizeof(T));
- return x->size() == count;
-}
-
} // namespace android
#endif // DATA_SOURCE_BASE_H_
diff --git a/media/libmediaextractor/include/media/MediaExtractor.h b/media/libmediaextractor/include/media/MediaExtractor.h
index 73c5f10..c329903 100644
--- a/media/libmediaextractor/include/media/MediaExtractor.h
+++ b/media/libmediaextractor/include/media/MediaExtractor.h
@@ -29,8 +29,6 @@
class DataSourceBase;
class MetaData;
-class String8;
-struct AMessage;
struct MediaSourceBase;
@@ -74,12 +72,6 @@
// CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
virtual uint32_t flags() const;
- // for DRM
- virtual char* getDrmTrackInfo(size_t /*trackID*/, int * /*len*/) {
- return NULL;
- }
- virtual void setUID(uid_t /*uid*/) {
- }
virtual status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) {
return INVALID_OPERATION;
}
@@ -87,14 +79,16 @@
virtual const char * name() { return "<unspecified>"; }
typedef MediaExtractor* (*CreatorFunc)(
- DataSourceBase *source, const sp<AMessage> &meta);
+ DataSourceBase *source, void *meta);
+ typedef void (*FreeMetaFunc)(void *meta);
- // The sniffer can optionally fill in "meta" with an AMessage containing
- // a dictionary of values that helps the corresponding extractor initialize
- // its state without duplicating effort already exerted by the sniffer.
+ // The sniffer can optionally fill in an opaque object, "meta", that helps
+ // the corresponding extractor initialize its state without duplicating
+ // effort already exerted by the sniffer. If "freeMeta" is given, it will be
+ // called against the opaque object when it is no longer used.
typedef CreatorFunc (*SnifferFunc)(
- DataSourceBase *source, String8 *mimeType,
- float *confidence, sp<AMessage> *meta);
+ DataSourceBase *source, float *confidence,
+ void **meta, FreeMetaFunc *freeMeta);
typedef struct {
const uint8_t b[16];
diff --git a/media/libmediaextractor/include/media/MediaSourceBase.h b/media/libmediaextractor/include/media/MediaSourceBase.h
index 9db6099..ab56613 100644
--- a/media/libmediaextractor/include/media/MediaSourceBase.h
+++ b/media/libmediaextractor/include/media/MediaSourceBase.h
@@ -30,7 +30,7 @@
namespace android {
-class MediaBuffer;
+class MediaBufferBase;
class SourceBaseAllocTracker {
public:
@@ -111,7 +111,7 @@
// MediaSource has changed mid-stream, the client can continue reading
// but should be prepared for buffers of the new configuration.
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
+ MediaBufferBase **buffer, const ReadOptions *options = NULL) = 0;
// Causes this source to suspend pulling data from its upstream source
// until a subsequent read-with-seek. This is currently not supported
diff --git a/media/libmediaextractor/include/media/stagefright/MediaBuffer.h b/media/libmediaextractor/include/media/stagefright/MediaBuffer.h
index a8f8375..85b4521 100644
--- a/media/libmediaextractor/include/media/stagefright/MediaBuffer.h
+++ b/media/libmediaextractor/include/media/stagefright/MediaBuffer.h
@@ -26,6 +26,7 @@
#include <binder/MemoryDealer.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
+#include <media/stagefright/MediaBufferBase.h>
namespace android {
@@ -34,19 +35,7 @@
class MediaBufferObserver;
class MetaData;
-class MediaBufferObserver {
-public:
- MediaBufferObserver() {}
- virtual ~MediaBufferObserver() {}
-
- virtual void signalBufferReturned(MediaBuffer *buffer) = 0;
-
-private:
- MediaBufferObserver(const MediaBufferObserver &);
- MediaBufferObserver &operator=(const MediaBufferObserver &);
-};
-
-class MediaBuffer {
+class MediaBuffer : public MediaBufferBase {
public:
// allocations larger than or equal to this will use shared memory.
static const size_t kSharedMemThreshold = 64 * 1024;
@@ -70,42 +59,42 @@
//
// If no MediaBufferGroup is set, the local reference count must be zero
// when called, whereupon the MediaBuffer is deleted.
- void release();
+ virtual void release();
// Increments the local reference count.
// Use only when MediaBufferGroup is set.
- void add_ref();
+ virtual void add_ref();
- void *data() const;
- size_t size() const;
+ virtual void *data() const;
+ virtual size_t size() const;
- size_t range_offset() const;
- size_t range_length() const;
+ virtual size_t range_offset() const;
+ virtual size_t range_length() const;
- void set_range(size_t offset, size_t length);
+ virtual void set_range(size_t offset, size_t length);
- sp<MetaData> meta_data();
+ virtual sp<MetaData> meta_data();
// Clears meta data and resets the range to the full extent.
- void reset();
+ virtual void reset();
- void setObserver(MediaBufferObserver *group);
+ virtual void setObserver(MediaBufferObserver *group);
// Returns a clone of this MediaBuffer increasing its reference count.
// The clone references the same data but has its own range and
// MetaData.
- MediaBuffer *clone();
+ virtual MediaBufferBase *clone();
// sum of localRefcount() and remoteRefcount()
- int refcount() const {
+ virtual int refcount() const {
return localRefcount() + remoteRefcount();
}
- int localRefcount() const {
+ virtual int localRefcount() const {
return mRefCount;
}
- int remoteRefcount() const {
+ virtual int remoteRefcount() const {
if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
int32_t remoteRefcount =
reinterpret_cast<SharedControl *>(mMemory->pointer())->getRemoteRefcount();
diff --git a/media/libmediaextractor/include/media/stagefright/MediaBufferBase.h b/media/libmediaextractor/include/media/stagefright/MediaBufferBase.h
new file mode 100644
index 0000000..81dd7d9
--- /dev/null
+++ b/media/libmediaextractor/include/media/stagefright/MediaBufferBase.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2009 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 MEDIA_BUFFER_BASE_H_
+
+#define MEDIA_BUFFER_BASE_H_
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+class MediaBufferBase;
+class MetaData;
+
+class MediaBufferObserver {
+public:
+ MediaBufferObserver() {}
+ virtual ~MediaBufferObserver() {}
+
+ virtual void signalBufferReturned(MediaBufferBase *buffer) = 0;
+
+private:
+ MediaBufferObserver(const MediaBufferObserver &);
+ MediaBufferObserver &operator=(const MediaBufferObserver &);
+};
+
+class MediaBufferBase {
+public:
+ static MediaBufferBase *Create(size_t size);
+
+ // If MediaBufferGroup is set, decrement the local reference count;
+ // if the local reference count drops to 0, return the buffer to the
+ // associated MediaBufferGroup.
+ //
+ // If no MediaBufferGroup is set, the local reference count must be zero
+ // when called, whereupon the MediaBuffer is deleted.
+ virtual void release() = 0;
+
+ // Increments the local reference count.
+ // Use only when MediaBufferGroup is set.
+ virtual void add_ref() = 0;
+
+ virtual void *data() const = 0;
+ virtual size_t size() const = 0;
+
+ virtual size_t range_offset() const = 0;
+ virtual size_t range_length() const = 0;
+
+ virtual void set_range(size_t offset, size_t length) = 0;
+
+ virtual sp<MetaData> meta_data() = 0;
+
+ // Clears meta data and resets the range to the full extent.
+ virtual void reset() = 0;
+
+ virtual void setObserver(MediaBufferObserver *group) = 0;
+
+ // Returns a clone of this MediaBufferBase increasing its reference
+ // count. The clone references the same data but has its own range and
+ // MetaData.
+ virtual MediaBufferBase *clone() = 0;
+
+ virtual int refcount() const = 0;
+
+ virtual int localRefcount() const = 0;
+ virtual int remoteRefcount() const = 0;
+
+ virtual ~MediaBufferBase() {};
+};
+
+} // namespace android
+
+#endif // MEDIA_BUFFER_BASE_H_
diff --git a/media/libmediaextractor/include/media/stagefright/MediaBufferGroup.h b/media/libmediaextractor/include/media/stagefright/MediaBufferGroup.h
index 3041181..75d5df7 100644
--- a/media/libmediaextractor/include/media/stagefright/MediaBufferGroup.h
+++ b/media/libmediaextractor/include/media/stagefright/MediaBufferGroup.h
@@ -18,13 +18,15 @@
#define MEDIA_BUFFER_GROUP_H_
-#include <media/stagefright/MediaBuffer.h>
+#include <list>
+
+#include <media/stagefright/MediaBufferBase.h>
#include <utils/Errors.h>
#include <utils/threads.h>
namespace android {
-class MediaBuffer;
+class MediaBufferBase;
class MediaBufferGroup : public MediaBufferObserver {
public:
@@ -35,7 +37,7 @@
~MediaBufferGroup();
- void add_buffer(MediaBuffer *buffer);
+ void add_buffer(MediaBufferBase *buffer);
bool has_buffers();
@@ -48,20 +50,16 @@
// If requestedSize is > 0, the returned MediaBuffer should have buffer
// size of at least requstedSize.
status_t acquire_buffer(
- MediaBuffer **buffer, bool nonBlocking = false, size_t requestedSize = 0);
+ MediaBufferBase **buffer, bool nonBlocking = false, size_t requestedSize = 0);
- size_t buffers() const { return mBuffers.size(); }
+ size_t buffers() const;
// If buffer is nullptr, have acquire_buffer() check for remote release.
- virtual void signalBufferReturned(MediaBuffer *buffer);
+ virtual void signalBufferReturned(MediaBufferBase *buffer);
private:
- friend class MediaBuffer;
-
- Mutex mLock;
- Condition mCondition;
- size_t mGrowthLimit; // Do not automatically grow group larger than this.
- std::list<MediaBuffer *> mBuffers;
+ struct InternalData;
+ InternalData *mInternal;
MediaBufferGroup(const MediaBufferGroup &);
MediaBufferGroup &operator=(const MediaBufferGroup &);
diff --git a/media/libmediaextractor/include/media/stagefright/MetaData.h b/media/libmediaextractor/include/media/stagefright/MetaData.h
index e4a84b7..7562a72 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaData.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaData.h
@@ -149,8 +149,6 @@
// To store the timed text format data
kKeyTextFormatData = 'text', // raw data
- kKeyRequiresSecureBuffers = 'secu', // bool (int32_t)
-
kKeyIsADTS = 'adts', // bool (int32_t)
kKeyAACAOT = 'aaot', // int32_t
@@ -258,16 +256,16 @@
int32_t left, int32_t top,
int32_t right, int32_t bottom);
- bool findCString(uint32_t key, const char **value);
- bool findInt32(uint32_t key, int32_t *value);
- bool findInt64(uint32_t key, int64_t *value);
- bool findFloat(uint32_t key, float *value);
- bool findPointer(uint32_t key, void **value);
+ bool findCString(uint32_t key, const char **value) const;
+ bool findInt32(uint32_t key, int32_t *value) const;
+ bool findInt64(uint32_t key, int64_t *value) const;
+ bool findFloat(uint32_t key, float *value) const;
+ bool findPointer(uint32_t key, void **value) const;
bool findRect(
uint32_t key,
int32_t *left, int32_t *top,
- int32_t *right, int32_t *bottom);
+ int32_t *right, int32_t *bottom) const;
bool setData(uint32_t key, uint32_t type, const void *data, size_t size);
diff --git a/media/libmediaplayer2/JAudioTrack.cpp b/media/libmediaplayer2/JAudioTrack.cpp
index 6d9605a..ac0cc57 100644
--- a/media/libmediaplayer2/JAudioTrack.cpp
+++ b/media/libmediaplayer2/JAudioTrack.cpp
@@ -32,6 +32,8 @@
uint32_t sampleRate, // AudioFormat && bufferSizeInBytes
audio_format_t format, // AudioFormat && bufferSizeInBytes
audio_channel_mask_t channelMask, // AudioFormat && bufferSizeInBytes
+ callback_t cbf, // Offload
+ void* user, // Offload
size_t frameCount, // bufferSizeInBytes
audio_session_t sessionId, // AudioTrack
const audio_attributes_t* pAttributes, // AudioAttributes
@@ -90,8 +92,27 @@
jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetSessionId, sessionId);
}
+ if (cbf != NULL) {
+ jmethodID jSetOffloadedPlayback = env->GetMethodID(jBuilderCls, "setOffloadedPlayback",
+ "(Z)Landroid/media/AudioTrack$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetOffloadedPlayback, true);
+ mFlags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+ }
+
jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioTrack;");
mAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
+
+ if (cbf != NULL) {
+ // Set offload mode callback
+ jobject jStreamEventCallbackObj = createStreamEventCallback(cbf, user);
+ jobject jExecutorObj = createCallbackExecutor();
+ jmethodID jSetStreamEventCallback = env->GetMethodID(
+ jAudioTrackCls,
+ "setStreamEventCallback",
+ "(Ljava/util/concurrent/Executor;Landroid/media/AudioTrack$StreamEventCallback;)V");
+ env->CallVoidMethod(
+ mAudioTrackObj, jSetStreamEventCallback, jExecutorObj, jStreamEventCallbackObj);
+ }
}
JAudioTrack::~JAudioTrack() {
@@ -160,6 +181,11 @@
return true;
}
+status_t JAudioTrack::getTimestamp(ExtendedTimestamp *timestamp __unused) {
+ // TODO: Implement this after appropriate Java AudioTrack method is available.
+ return NO_ERROR;
+}
+
status_t JAudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) {
// TODO: existing native AudioTrack returns INVALID_OPERATION on offload/direct/fast tracks.
// Should we do the same thing?
@@ -442,6 +468,80 @@
return routedDeviceId;
}
+audio_session_t JAudioTrack::getAudioSessionId() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jmethodID jGetAudioSessionId = env->GetMethodID(mAudioTrackCls, "getAudioSessionId", "()I");
+ jint sessionId = env->CallIntMethod(mAudioTrackObj, jGetAudioSessionId);
+ return (audio_session_t) sessionId;
+}
+
+status_t JAudioTrack::setOutputDevice(audio_port_handle_t deviceId) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass jMP2ImplCls = env->FindClass("android/media/MediaPlayer2Impl");
+ jmethodID jSetAudioOutputDeviceById = env->GetMethodID(
+ jMP2ImplCls, "setAudioOutputDeviceById", "(Landroid/media/AudioTrack;I)Z");
+ jboolean result = env->CallStaticBooleanMethod(
+ jMP2ImplCls, jSetAudioOutputDeviceById, mAudioTrackObj, deviceId);
+ return result == true ? NO_ERROR : BAD_VALUE;
+}
+
+status_t JAudioTrack::pendingDuration(int32_t *msec) {
+ if (msec == nullptr) {
+ return BAD_VALUE;
+ }
+
+ bool isPurePcmData = audio_is_linear_pcm(format()) && (getFlags() & AUDIO_FLAG_HW_AV_SYNC) == 0;
+ if (!isPurePcmData) {
+ return INVALID_OPERATION;
+ }
+
+ // TODO: Need to know the difference btw. client and server time.
+ // If getTimestamp(ExtendedTimestamp) is ready, and un-comment below and modify appropriately.
+ // (copied from AudioTrack.cpp)
+
+// ExtendedTimestamp ets;
+// ExtendedTimestamp::LOCATION location = ExtendedTimestamp::LOCATION_SERVER;
+// if (getTimestamp_l(&ets) == OK && ets.mTimeNs[location] > 0) {
+// int64_t diff = ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT]
+// - ets.mPosition[location];
+// if (diff < 0) {
+// *msec = 0;
+// } else {
+// // ms is the playback time by frames
+// int64_t ms = (int64_t)((double)diff * 1000 /
+// ((double)mSampleRate * mPlaybackRate.mSpeed));
+// // clockdiff is the timestamp age (negative)
+// int64_t clockdiff = (mState != STATE_ACTIVE) ? 0 :
+// ets.mTimeNs[location]
+// + ets.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_MONOTONIC]
+// - systemTime(SYSTEM_TIME_MONOTONIC);
+//
+// //ALOGV("ms: %lld clockdiff: %lld", (long long)ms, (long long)clockdiff);
+// static const int NANOS_PER_MILLIS = 1000000;
+// *msec = (int32_t)(ms + clockdiff / NANOS_PER_MILLIS);
+// }
+// return NO_ERROR;
+// }
+
+ return NO_ERROR;
+}
+
+status_t JAudioTrack::addAudioDeviceCallback(
+ const sp<AudioSystem::AudioDeviceCallback>& callback __unused) {
+ // TODO: Implement this after appropriate Java AudioTrack method is available.
+ return NO_ERROR;
+}
+
+status_t JAudioTrack::removeAudioDeviceCallback(
+ const sp<AudioSystem::AudioDeviceCallback>& callback __unused) {
+ // TODO: Implement this after appropriate Java AudioTrack method is available.
+ return NO_ERROR;
+}
+
+/////////////////////////////////////////////////////////////
+/// Private method begins ///
+/////////////////////////////////////////////////////////////
+
jobject JAudioTrack::createVolumeShaperConfigurationObj(
const sp<media::VolumeShaper::Configuration>& config) {
@@ -546,6 +646,24 @@
return env->CallObjectMethod(jBuilderObj, jBuild);
}
+jobject JAudioTrack::createStreamEventCallback(callback_t cbf, void* user) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass jCallbackCls = env->FindClass("android/media/MediaPlayer2Impl$StreamEventCallback");
+ jmethodID jCallbackCtor = env->GetMethodID(jCallbackCls, "<init>", "(JJJ)V");
+ jobject jCallbackObj = env->NewObject(jCallbackCls, jCallbackCtor, this, cbf, user);
+ return jCallbackObj;
+}
+
+jobject JAudioTrack::createCallbackExecutor() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass jExecutorsCls = env->FindClass("java/util/concurrent/Executors");
+ jmethodID jNewSingleThreadExecutor = env->GetStaticMethodID(jExecutorsCls,
+ "newSingleThreadExecutor", "()Ljava/util/concurrent/ExecutorService;");
+ jobject jSingleThreadExecutorObj =
+ env->CallStaticObjectMethod(jExecutorsCls, jNewSingleThreadExecutor);
+ return jSingleThreadExecutorObj;
+}
+
status_t JAudioTrack::javaToNativeStatus(int javaStatus) {
switch (javaStatus) {
case AUDIO_JAVA_SUCCESS:
diff --git a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h b/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
index 10fa5e8..301825b 100644
--- a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
+++ b/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
@@ -19,6 +19,7 @@
#include <jni.h>
#include <media/AudioResamplerPublic.h>
+#include <media/AudioSystem.h>
#include <media/VolumeShaper.h>
#include <system/audio.h>
#include <utils/Errors.h>
@@ -31,6 +32,42 @@
class JAudioTrack {
public:
+ /* Events used by AudioTrack callback function (callback_t).
+ * Keep in sync with frameworks/base/media/java/android/media/AudioTrack.java NATIVE_EVENT_*.
+ */
+ enum event_type {
+ EVENT_MORE_DATA = 0, // Request to write more data to buffer.
+ EVENT_NEW_IAUDIOTRACK = 6, // IAudioTrack was re-created, either due to re-routing and
+ // voluntary invalidation by mediaserver, or mediaserver crash.
+ EVENT_STREAM_END = 7, // Sent after all the buffers queued in AF and HW are played
+ // back (after stop is called) for an offloaded track.
+ };
+
+ class Buffer
+ {
+ public:
+ size_t mSize; // input/output in bytes.
+ void* mData; // pointer to the audio data.
+ };
+
+ /* As a convenience, if a callback is supplied, a handler thread
+ * is automatically created with the appropriate priority. This thread
+ * invokes the callback when a new buffer becomes available or various conditions occur.
+ *
+ * Parameters:
+ *
+ * event: type of event notified (see enum AudioTrack::event_type).
+ * user: Pointer to context for use by the callback receiver.
+ * info: Pointer to optional parameter according to event type:
+ * - EVENT_MORE_DATA: pointer to JAudioTrack::Buffer struct. The callback must not
+ * write more bytes than indicated by 'size' field and update 'size' if fewer bytes
+ * are written.
+ * - EVENT_NEW_IAUDIOTRACK: unused.
+ * - EVENT_STREAM_END: unused.
+ */
+
+ typedef void (*callback_t)(int event, void* user, void *info);
+
/* Creates an JAudioTrack object for non-offload mode.
* Once created, the track needs to be started before it can be used.
* Unspecified values are set to appropriate default values.
@@ -49,6 +86,9 @@
* output sink.
* (TODO: How can we check whether a format is supported?)
* channelMask: Channel mask, such that audio_is_output_channel(channelMask) is true.
+ * cbf: Callback function. If not null, this function is called periodically
+ * to provide new data and inform of marker, position updates, etc.
+ * user: Context for use by the callback receiver.
* frameCount: Minimum size of track PCM buffer in frames. This defines the
* application's contribution to the latency of the track.
* The actual size selected by the JAudioTrack could be larger if the
@@ -68,35 +108,20 @@
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
+ callback_t cbf,
+ void* user,
size_t frameCount = 0,
audio_session_t sessionId = AUDIO_SESSION_ALLOCATE,
const audio_attributes_t* pAttributes = NULL,
float maxRequiredSpeed = 1.0f);
/*
- Temporarily removed constructor arguments:
-
- // Q. Values are in audio-base.h, but where can we find explanation for them?
- audio_output_flags_t flags,
-
// Q. May be used in AudioTrack.setPreferredDevice(AudioDeviceInfo)?
audio_port_handle_t selectedDeviceId,
- // Should be deleted, since we don't use Binder anymore.
- bool doNotReconnect,
-
- // Do we need UID and PID?
- uid_t uid,
- pid_t pid,
-
- // TODO: Uses these values when Java AudioTrack supports the offload mode.
- callback_t cbf,
- void* user,
+ // TODO: No place to use these values.
int32_t notificationFrames,
const audio_offload_info_t *offloadInfo,
-
- // Fixed to false, but what is this?
- threadCanCallJava
*/
virtual ~JAudioTrack();
@@ -138,6 +163,46 @@
*/
bool getTimestamp(AudioTimestamp& timestamp);
+ // TODO: This doc is just copied from AudioTrack.h. Revise it after implemenation.
+ /* Return the extended timestamp, with additional timebase info and improved drain behavior.
+ *
+ * This is similar to the AudioTrack.java API:
+ * getTimestamp(@NonNull AudioTimestamp timestamp, @AudioTimestamp.Timebase int timebase)
+ *
+ * Some differences between this method and the getTimestamp(AudioTimestamp& timestamp) method
+ *
+ * 1. stop() by itself does not reset the frame position.
+ * A following start() resets the frame position to 0.
+ * 2. flush() by itself does not reset the frame position.
+ * The frame position advances by the number of frames flushed,
+ * when the first frame after flush reaches the audio sink.
+ * 3. BOOTTIME clock offsets are provided to help synchronize with
+ * non-audio streams, e.g. sensor data.
+ * 4. Position is returned with 64 bits of resolution.
+ *
+ * Parameters:
+ * timestamp: A pointer to the caller allocated ExtendedTimestamp.
+ *
+ * Returns NO_ERROR on success; timestamp is filled with valid data.
+ * BAD_VALUE if timestamp is NULL.
+ * WOULD_BLOCK if called immediately after start() when the number
+ * of frames consumed is less than the
+ * overall hardware latency to physical output. In WOULD_BLOCK cases,
+ * one might poll again, or use getPosition(), or use 0 position and
+ * current time for the timestamp.
+ * If WOULD_BLOCK is returned, the timestamp is still
+ * modified with the LOCATION_CLIENT portion filled.
+ * DEAD_OBJECT if AudioFlinger dies or the output device changes and
+ * the track cannot be automatically restored.
+ * The application needs to recreate the AudioTrack
+ * because the audio device changed or AudioFlinger died.
+ * This typically occurs for direct or offloaded tracks
+ * or if mDoNotReconnect is true.
+ * INVALID_OPERATION if called on a offloaded or direct track.
+ * Use getTimestamp(AudioTimestamp& timestamp) instead.
+ */
+ status_t getTimestamp(ExtendedTimestamp *timestamp);
+
/* Set source playback rate for timestretch
* 1.0 is normal speed: < 1.0 is slower, > 1.0 is faster
* 1.0 is normal pitch: < 1.0 is lower pitch, > 1.0 is higher pitch
@@ -270,7 +335,65 @@
*/
audio_port_handle_t getRoutedDeviceId();
+ /* Returns the ID of the audio session this AudioTrack belongs to. */
+ audio_session_t getAudioSessionId();
+
+ /* Selects the audio device to use for output of this AudioTrack. A value of
+ * AUDIO_PORT_HANDLE_NONE indicates default routing.
+ *
+ * Parameters:
+ * The device ID of the selected device (as returned by the AudioDevicesManager API).
+ *
+ * Returned value:
+ * - NO_ERROR: successful operation
+ * - BAD_VALUE: failed to find the valid output device with given device Id.
+ */
+ status_t setOutputDevice(audio_port_handle_t deviceId);
+
+ // TODO: Add AUDIO_OUTPUT_FLAG_DIRECT when it is possible to check.
+ // TODO: Add AUDIO_FLAG_HW_AV_SYNC when it is possible to check.
+ /* Returns the flags */
+ audio_output_flags_t getFlags() const { return mFlags; }
+
+ /* Obtain the pending duration in milliseconds for playback of pure PCM data remaining in
+ * AudioTrack.
+ *
+ * Returns NO_ERROR if successful.
+ * INVALID_OPERATION if the AudioTrack does not contain pure PCM data.
+ * BAD_VALUE if msec is nullptr.
+ */
+ status_t pendingDuration(int32_t *msec);
+
+ /* Adds an AudioDeviceCallback. The caller will be notified when the audio device to which this
+ * AudioTrack is routed is updated.
+ * Replaces any previously installed callback.
+ *
+ * Parameters:
+ *
+ * callback: The callback interface
+ *
+ * Returns NO_ERROR if successful.
+ * INVALID_OPERATION if the same callback is already installed.
+ * NO_INIT or PREMISSION_DENIED if AudioFlinger service is not reachable
+ * BAD_VALUE if the callback is NULL
+ */
+ status_t addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
+
+ /* Removes an AudioDeviceCallback.
+ *
+ * Parameters:
+ *
+ * callback: The callback interface
+ *
+ * Returns NO_ERROR if successful.
+ * INVALID_OPERATION if the callback is not installed
+ * BAD_VALUE if the callback is NULL
+ */
+ status_t removeAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
+
private:
+ audio_output_flags_t mFlags;
+
jclass mAudioTrackCls;
jobject mAudioTrackObj;
@@ -282,6 +405,12 @@
jobject createVolumeShaperOperationObj(
const sp<media::VolumeShaper::Operation>& operation);
+ /* Creates a Java StreamEventCallback object */
+ jobject createStreamEventCallback(callback_t cbf, void* user);
+
+ /* Creates a Java Executor object for running a callback */
+ jobject createCallbackExecutor();
+
status_t javaToNativeStatus(int javaStatus);
};
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
index 4700660..c34aabb 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
@@ -1149,7 +1149,7 @@
}
sp<ABuffer> NuPlayer2::GenericSource2::mediaBufferToABuffer(
- MediaBuffer* mb,
+ MediaBufferBase* mb,
media_track_type trackType) {
bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
size_t outLength = mb->range_length();
@@ -1333,7 +1333,7 @@
int32_t generation = getDataGeneration(trackType);
for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
- Vector<MediaBuffer *> mediaBuffers;
+ Vector<MediaBufferBase *> mediaBuffers;
status_t err = NO_ERROR;
sp<IMediaSource> source = track->mSource;
@@ -1342,7 +1342,7 @@
err = source->readMultiple(
&mediaBuffers, maxBuffers - numBuffers, &options);
} else {
- MediaBuffer *mbuf = NULL;
+ MediaBufferBase *mbuf = NULL;
err = source->read(&mbuf, &options);
if (err == OK && mbuf != NULL) {
mediaBuffers.push_back(mbuf);
@@ -1365,7 +1365,7 @@
for (; id < count; ++id) {
int64_t timeUs;
- MediaBuffer *mbuf = mediaBuffers[id];
+ MediaBufferBase *mbuf = mediaBuffers[id];
if (!mbuf->meta_data()->findInt64(kKeyTime, &timeUs)) {
mbuf->meta_data()->dumpToLog();
track->mPackets->signalEOS(ERROR_MALFORMED);
@@ -1659,7 +1659,7 @@
return OK;
}
-void NuPlayer2::GenericSource2::signalBufferReturned(MediaBuffer *buffer)
+void NuPlayer2::GenericSource2::signalBufferReturned(MediaBufferBase *buffer)
{
//ALOGV("signalBufferReturned %p refCount: %d", buffer, buffer->localRefcount());
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.h b/media/libmediaplayer2/nuplayer2/GenericSource2.h
index 1a5409a..896c397 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.h
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.h
@@ -86,7 +86,7 @@
virtual bool isStreaming() const;
// Modular DRM
- virtual void signalBufferReturned(MediaBuffer *buffer);
+ virtual void signalBufferReturned(MediaBufferBase *buffer);
virtual status_t prepareDrm(
const uint8_t uuid[16],
@@ -202,7 +202,7 @@
int32_t curGen, const sp<AnotherPacketSource>& packets, const sp<AMessage>& msg);
sp<ABuffer> mediaBufferToABuffer(
- MediaBuffer *mbuf,
+ MediaBufferBase *mbuf,
media_track_type trackType);
void postReadBuffer(media_track_type trackType);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
index a436592..c49bccb 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
@@ -1066,7 +1066,7 @@
}
// Modular DRM
- MediaBuffer *mediaBuf = NULL;
+ MediaBufferBase *mediaBuf = NULL;
sp<AMediaCodecCryptoInfoWrapper> cryptInfo;
// copy into codec buffer
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 511f46f..b0c82f2 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -1143,7 +1143,7 @@
}
sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
- MediaBuffer* mb,
+ MediaBufferBase* mb,
media_track_type trackType) {
bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
size_t outLength = mb->range_length();
@@ -1326,7 +1326,7 @@
int32_t generation = getDataGeneration(trackType);
for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
- Vector<MediaBuffer *> mediaBuffers;
+ Vector<MediaBufferBase *> mediaBuffers;
status_t err = NO_ERROR;
sp<IMediaSource> source = track->mSource;
@@ -1335,7 +1335,7 @@
err = source->readMultiple(
&mediaBuffers, maxBuffers - numBuffers, &options);
} else {
- MediaBuffer *mbuf = NULL;
+ MediaBufferBase *mbuf = NULL;
err = source->read(&mbuf, &options);
if (err == OK && mbuf != NULL) {
mediaBuffers.push_back(mbuf);
@@ -1358,7 +1358,7 @@
for (; id < count; ++id) {
int64_t timeUs;
- MediaBuffer *mbuf = mediaBuffers[id];
+ MediaBufferBase *mbuf = mediaBuffers[id];
if (!mbuf->meta_data()->findInt64(kKeyTime, &timeUs)) {
mbuf->meta_data()->dumpToLog();
track->mPackets->signalEOS(ERROR_MALFORMED);
@@ -1654,7 +1654,7 @@
return OK;
}
-void NuPlayer::GenericSource::signalBufferReturned(MediaBuffer *buffer)
+void NuPlayer::GenericSource::signalBufferReturned(MediaBufferBase *buffer)
{
//ALOGV("signalBufferReturned %p refCount: %d", buffer, buffer->localRefcount());
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 2406665..065cac1 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -86,7 +86,7 @@
virtual bool isStreaming() const;
// Modular DRM
- virtual void signalBufferReturned(MediaBuffer *buffer);
+ virtual void signalBufferReturned(MediaBufferBase *buffer);
virtual status_t prepareDrm(
const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *outCrypto);
@@ -201,7 +201,7 @@
int32_t curGen, const sp<AnotherPacketSource>& packets, const sp<AMessage>& msg);
sp<ABuffer> mediaBufferToABuffer(
- MediaBuffer *mbuf,
+ MediaBufferBase *mbuf,
media_track_type trackType);
void postReadBuffer(media_track_type trackType);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 1aca96c..88594d2 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -1046,7 +1046,7 @@
}
// Modular DRM
- MediaBuffer *mediaBuf = NULL;
+ MediaBufferBase *mediaBuf = NULL;
NuPlayerDrm::CryptoInfo *cryptInfo = NULL;
// copy into codec buffer
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index 281af47..d64138e 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -294,7 +294,7 @@
prctl(PR_SET_NAME, (unsigned long)"AACWriterThread", 0, 0, 0);
while (!mDone && err == OK) {
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
err = mSource->read(&buffer);
if (err != OK) {
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 910abc6..e33d3da 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -193,7 +193,7 @@
prctl(PR_SET_NAME, (unsigned long)"AMRWriter", 0, 0, 0);
while (!mDone) {
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
err = mSource->read(&buffer);
if (err != OK) {
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 08b2775..905817f 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -60,6 +60,7 @@
"AudioPresentationInfo.cpp",
"AudioSource.cpp",
"BufferImpl.cpp",
+ "C2OMXNode.cpp",
"CCodec.cpp",
"CCodecBufferChannel.cpp",
"CodecBase.cpp",
@@ -130,7 +131,6 @@
"libui",
"libutils",
"libmedia_helper",
- "libstagefright_bufferqueue_helper",
"libstagefright_codec2",
"libstagefright_codec2_vndk",
"libstagefright_foundation",
@@ -149,6 +149,10 @@
"android.hardware.media.omx@1.0",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.mapper@2.0",
+
+ // TODO: do not link directly with impl
+ "android.hardware.media.c2@1.0-service-impl",
+ "libstagefright_bufferqueue_helper",
],
static_libs: [
@@ -215,6 +219,7 @@
"InterfaceUtils.cpp",
"MediaClock.cpp",
"MediaExtractorFactory.cpp",
+ "NdkUtils.cpp",
"NuCachedSource2.cpp",
"RemoteMediaExtractor.cpp",
"RemoteMediaSource.cpp",
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 70ce38c..d854582 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -240,7 +240,7 @@
}
status_t AudioSource::read(
- MediaBuffer **out, const ReadOptions * /* options */) {
+ MediaBufferBase **out, const ReadOptions * /* options */) {
Mutex::Autolock autoLock(mLock);
*out = NULL;
@@ -311,7 +311,7 @@
return OK;
}
-void AudioSource::signalBufferReturned(MediaBuffer *buffer) {
+void AudioSource::signalBufferReturned(MediaBufferBase *buffer) {
ALOGV("signalBufferReturned: %p", buffer->data());
Mutex::Autolock autoLock(mLock);
--mNumClientOwnedBuffers;
diff --git a/media/libstagefright/C2OMXNode.cpp b/media/libstagefright/C2OMXNode.cpp
new file mode 100644
index 0000000..e6f81af
--- /dev/null
+++ b/media/libstagefright/C2OMXNode.cpp
@@ -0,0 +1,281 @@
+/*
+ * Copyright 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.
+ */
+
+#ifdef __LP64__
+#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+#endif
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2OMXNode"
+#include <log/log.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2BlockInternal.h>
+#include <C2Component.h>
+#include <C2PlatformSupport.h>
+
+#include <OMX_Component.h>
+#include <OMX_Index.h>
+#include <OMX_IndexExt.h>
+
+#include <media/stagefright/omx/OMXUtils.h>
+#include <media/stagefright/MediaErrors.h>
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+
+#include "include/C2OMXNode.h"
+
+namespace android {
+
+namespace {
+
+class Buffer2D : public C2Buffer {
+public:
+ explicit Buffer2D(C2ConstGraphicBlock block) : C2Buffer({ block }) {}
+};
+
+} // namespace
+
+C2OMXNode::C2OMXNode(const std::shared_ptr<C2Component> &comp) : mComp(comp) {}
+
+status_t C2OMXNode::freeNode() {
+ mComp.reset();
+ return OK;
+}
+
+status_t C2OMXNode::sendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) {
+ (void)cmd;
+ (void)param;
+ return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::getParameter(OMX_INDEXTYPE index, void *params, size_t size) {
+ status_t err = ERROR_UNSUPPORTED;
+ switch ((uint32_t)index) {
+ case OMX_IndexParamConsumerUsageBits: {
+ // TODO: read from intf()
+ OMX_U32 *usage = (OMX_U32 *)params;
+ *usage = GRALLOC_USAGE_SW_READ_OFTEN;
+ err = OK;
+ break;
+ }
+ case OMX_IndexParamPortDefinition: {
+ if (size < sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) {
+ return BAD_VALUE;
+ }
+ OMX_PARAM_PORTDEFINITIONTYPE *pDef = (OMX_PARAM_PORTDEFINITIONTYPE *)params;
+ // TODO: read these from intf()
+ pDef->nBufferCountActual = 16;
+ pDef->eDomain = OMX_PortDomainVideo;
+ pDef->format.video.nFrameWidth = 1080;
+ pDef->format.video.nFrameHeight = 1920;
+ err = OK;
+ break;
+ }
+ default:
+ break;
+ }
+ return err;
+}
+
+status_t C2OMXNode::setParameter(OMX_INDEXTYPE index, const void *params, size_t size) {
+ (void)index;
+ (void)params;
+ (void)size;
+ return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::getConfig(OMX_INDEXTYPE index, void *config, size_t size) {
+ (void)index;
+ (void)config;
+ (void)size;
+ return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::setConfig(OMX_INDEXTYPE index, const void *config, size_t size) {
+ (void)index;
+ (void)config;
+ (void)size;
+ return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::setPortMode(OMX_U32 portIndex, IOMX::PortMode mode) {
+ (void)portIndex;
+ (void)mode;
+ return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::prepareForAdaptivePlayback(
+ OMX_U32 portIndex, OMX_BOOL enable,
+ OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) {
+ (void)portIndex;
+ (void)enable;
+ (void)maxFrameWidth;
+ (void)maxFrameHeight;
+ return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::configureVideoTunnelMode(
+ OMX_U32 portIndex, OMX_BOOL tunneled,
+ OMX_U32 audioHwSync, native_handle_t **sidebandHandle) {
+ (void)portIndex;
+ (void)tunneled;
+ (void)audioHwSync;
+ *sidebandHandle = nullptr;
+ return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::getGraphicBufferUsage(OMX_U32 portIndex, OMX_U32* usage) {
+ (void)portIndex;
+ *usage = 0;
+ return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::setInputSurface(const sp<IOMXBufferSource> &bufferSource) {
+ c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
+ C2PlatformAllocatorStore::GRALLOC,
+ &mAllocator);
+ if (err != OK) {
+ return UNKNOWN_ERROR;
+ }
+ mBufferSource = bufferSource;
+ return OK;
+}
+
+status_t C2OMXNode::allocateSecureBuffer(
+ OMX_U32 portIndex, size_t size, buffer_id *buffer,
+ void **bufferData, sp<NativeHandle> *nativeHandle) {
+ (void)portIndex;
+ (void)size;
+ (void)nativeHandle;
+ *buffer = 0;
+ *bufferData = nullptr;
+ return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::useBuffer(
+ OMX_U32 portIndex, const OMXBuffer &omxBuf, buffer_id *buffer) {
+ (void)portIndex;
+ (void)omxBuf;
+ *buffer = 0;
+ return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::freeBuffer(OMX_U32 portIndex, buffer_id buffer) {
+ (void)portIndex;
+ (void)buffer;
+ return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::fillBuffer(
+ buffer_id buffer, const OMXBuffer &omxBuf, int fenceFd) {
+ (void)buffer;
+ (void)omxBuf;
+ (void)fenceFd;
+ return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::emptyBuffer(
+ buffer_id buffer, const OMXBuffer &omxBuf,
+ OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
+ // TODO: better fence handling
+ if (fenceFd >= 0) {
+ sp<Fence> fence = new Fence(fenceFd);
+ fence->waitForever(LOG_TAG);
+ }
+ std::shared_ptr<C2Component> comp = mComp.lock();
+ if (!comp) {
+ return NO_INIT;
+ }
+
+ uint32_t c2Flags = 0;
+ std::shared_ptr<C2GraphicBlock> block;
+
+ C2Handle *handle = nullptr;
+ if (omxBuf.mBufferType == OMXBuffer::kBufferTypeANWBuffer) {
+ std::shared_ptr<C2GraphicAllocation> alloc;
+ handle = WrapNativeCodec2GrallocHandle(
+ native_handle_clone(omxBuf.mGraphicBuffer->handle),
+ omxBuf.mGraphicBuffer->width,
+ omxBuf.mGraphicBuffer->height,
+ omxBuf.mGraphicBuffer->format,
+ omxBuf.mGraphicBuffer->usage,
+ omxBuf.mGraphicBuffer->stride);
+ c2_status_t err = mAllocator->priorGraphicAllocation(handle, &alloc);
+ if (err != OK) {
+ return UNKNOWN_ERROR;
+ }
+ block = _C2BlockFactory::CreateGraphicBlock(alloc);
+ } else if (flags & OMX_BUFFERFLAG_EOS) {
+ c2Flags = C2FrameData::FLAG_END_OF_STREAM;
+ } else {
+ return BAD_VALUE;
+ }
+
+ std::unique_ptr<C2Work> work(new C2Work);
+ work->input.flags = (C2FrameData::flags_t)c2Flags;
+ work->input.ordinal.timestamp = timestamp;
+ work->input.ordinal.frameIndex = mFrameIndex++;
+ work->input.buffers.clear();
+ if (block) {
+ std::shared_ptr<C2Buffer> c2Buffer(
+ // TODO: fence
+ new Buffer2D(block->share(
+ C2Rect(block->width(), block->height()), ::android::C2Fence())),
+ [handle, buffer, source = getSource()](C2Buffer *ptr) {
+ delete ptr;
+ native_handle_delete(handle);
+ // TODO: fence
+ (void)source->onInputBufferEmptied(buffer, -1);
+ });
+ work->input.buffers.push_back(c2Buffer);
+ }
+ work->worklets.clear();
+ work->worklets.emplace_back(new C2Worklet);
+ std::list<std::unique_ptr<C2Work>> items;
+ items.push_back(std::move(work));
+
+ c2_status_t err = comp->queue_nb(&items);
+ if (err != C2_OK) {
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+status_t C2OMXNode::getExtensionIndex(
+ const char *parameterName, OMX_INDEXTYPE *index) {
+ (void)parameterName;
+ *index = OMX_IndexMax;
+ return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::dispatchMessage(const omx_message& msg) {
+ if (msg.type != omx_message::EVENT) {
+ return ERROR_UNSUPPORTED;
+ }
+ if (msg.u.event_data.event != OMX_EventDataSpaceChanged) {
+ return ERROR_UNSUPPORTED;
+ }
+ // TODO: fill intf() with info inside |msg|.
+ return OK;
+}
+
+sp<IOMXBufferSource> C2OMXNode::getSource() {
+ return mBufferSource;
+}
+
+} // namespace android
diff --git a/media/libstagefright/CCodec.cpp b/media/libstagefright/CCodec.cpp
index 84e98f8..bb70458 100644
--- a/media/libstagefright/CCodec.cpp
+++ b/media/libstagefright/CCodec.cpp
@@ -24,17 +24,23 @@
#include <C2PlatformSupport.h>
#include <C2V4l2Support.h>
+#include <android/IOMXBufferSource.h>
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
#include <gui/Surface.h>
+#include <media/stagefright/codec2/1.0/InputSurface.h>
#include <media/stagefright/BufferProducerWrapper.h>
#include <media/stagefright/CCodec.h>
#include <media/stagefright/PersistentSurface.h>
+#include "include/C2OMXNode.h"
#include "include/CCodecBufferChannel.h"
-
-using namespace std::chrono_literals;
+#include "include/InputSurfaceWrapper.h"
namespace android {
+using namespace std::chrono_literals;
+using ::android::hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
+
namespace {
class CCodecWatchdog : public AHandler {
@@ -146,6 +152,76 @@
wp<CCodec> mCodec;
};
+class C2InputSurfaceWrapper : public InputSurfaceWrapper {
+public:
+ explicit C2InputSurfaceWrapper(const sp<InputSurface> &surface) : mSurface(surface) {}
+ ~C2InputSurfaceWrapper() override = default;
+
+ status_t connect(const std::shared_ptr<C2Component> &comp) override {
+ if (mConnection != nullptr) {
+ return ALREADY_EXISTS;
+ }
+ mConnection = mSurface->connectToComponent(comp);
+ return OK;
+ }
+
+ void disconnect() override {
+ if (mConnection != nullptr) {
+ mConnection->disconnect();
+ mConnection.clear();
+ }
+ }
+
+private:
+ sp<InputSurface> mSurface;
+ sp<InputSurfaceConnection> mConnection;
+};
+
+class GraphicBufferSourceWrapper : public InputSurfaceWrapper {
+public:
+ explicit GraphicBufferSourceWrapper(const sp<IGraphicBufferSource> &source) : mSource(source) {}
+ ~GraphicBufferSourceWrapper() override = default;
+
+ status_t connect(const std::shared_ptr<C2Component> &comp) override {
+ // TODO: proper color aspect & dataspace
+ android_dataspace dataSpace = HAL_DATASPACE_BT709;
+
+ mNode = new C2OMXNode(comp);
+ mSource->configure(mNode, dataSpace);
+
+ // TODO: configure according to intf().
+
+ sp<IOMXBufferSource> source = mNode->getSource();
+ if (source == nullptr) {
+ return NO_INIT;
+ }
+ constexpr size_t kNumSlots = 16;
+ for (size_t i = 0; i < kNumSlots; ++i) {
+ source->onInputBufferAdded(i);
+ }
+ source->onOmxExecuting();
+ return OK;
+ }
+
+ void disconnect() override {
+ if (mNode == nullptr) {
+ return;
+ }
+ sp<IOMXBufferSource> source = mNode->getSource();
+ if (source == nullptr) {
+ ALOGD("GBSWrapper::disconnect: node is not configured with OMXBufferSource.");
+ return;
+ }
+ source->onOmxIdle();
+ source->onOmxLoaded();
+ mNode.clear();
+ }
+
+private:
+ sp<IGraphicBufferSource> mSource;
+ sp<C2OMXNode> mNode;
+};
+
} // namespace
CCodec::CCodec()
@@ -300,18 +376,18 @@
}
void CCodec::createInputSurface() {
- sp<IGraphicBufferProducer> producer;
- sp<GraphicBufferSource> source(new GraphicBufferSource);
+ // TODO: get this from codec process
+ sp<InputSurface> surface(InputSurface::Create());
- status_t err = source->initCheck();
+ // TODO: get proper error code.
+ status_t err = (surface == nullptr) ? UNKNOWN_ERROR : OK;
if (err != OK) {
- ALOGE("Failed to initialize graphic buffer source: %d", err);
+ ALOGE("Failed to initialize input surface: %d", err);
mCallback->onInputSurfaceCreationFailed(err);
return;
}
- producer = source->getIGraphicBufferProducer();
- err = setupInputSurface(source);
+ err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(surface));
if (err != OK) {
ALOGE("Failed to set up input surface: %d", err);
mCallback->onInputSurfaceCreationFailed(err);
@@ -328,16 +404,16 @@
mCallback->onInputSurfaceCreated(
inputFormat,
outputFormat,
- new BufferProducerWrapper(producer));
+ new BufferProducerWrapper(new H2BGraphicBufferProducer(surface)));
}
-status_t CCodec::setupInputSurface(const sp<GraphicBufferSource> &source) {
- status_t err = mChannel->setGraphicBufferSource(source);
+status_t CCodec::setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface) {
+ status_t err = mChannel->setInputSurface(surface);
if (err != OK) {
return err;
}
- // TODO: configure |source| with other settings.
+ // TODO: configure |surface| with other settings.
return OK;
}
@@ -348,10 +424,22 @@
}
void CCodec::setInputSurface(const sp<PersistentSurface> &surface) {
- // TODO
- (void)surface;
+ status_t err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
+ surface->getBufferSource()));
+ if (err != OK) {
+ ALOGE("Failed to set up input surface: %d", err);
+ mCallback->onInputSurfaceDeclined(err);
+ return;
+ }
- mCallback->onInputSurfaceDeclined(ERROR_UNSUPPORTED);
+ sp<AMessage> inputFormat;
+ sp<AMessage> outputFormat;
+ {
+ Mutexed<Formats>::Locked formats(mFormats);
+ inputFormat = formats->inputFormat;
+ outputFormat = formats->outputFormat;
+ }
+ mCallback->onInputSurfaceAccepted(inputFormat, outputFormat);
}
void CCodec::initiateStart() {
diff --git a/media/libstagefright/CCodecBufferChannel.cpp b/media/libstagefright/CCodecBufferChannel.cpp
index 27060e1..6fba890 100644
--- a/media/libstagefright/CCodecBufferChannel.cpp
+++ b/media/libstagefright/CCodecBufferChannel.cpp
@@ -101,15 +101,6 @@
* Release the buffer obtained from requestNewBuffer() and get the
* associated C2Buffer object back. Returns empty shared_ptr if the
* buffer is not on file.
- *
- * XXX: this is a quick hack to be removed
- */
- virtual std::shared_ptr<C2Buffer> releaseBufferIndex(size_t /* index */) { return nullptr; }
-
- /**
- * Release the buffer obtained from requestNewBuffer() and get the
- * associated C2Buffer object back. Returns empty shared_ptr if the
- * buffer is not on file.
*/
virtual std::shared_ptr<C2Buffer> releaseBuffer(const sp<MediaCodecBuffer> &buffer) = 0;
@@ -134,47 +125,6 @@
DISALLOW_EVIL_CONSTRUCTORS(InputBuffers);
};
-class CCodecBufferChannel::InputBufferClient {
-public:
- explicit InputBufferClient(
- const std::shared_ptr<CCodecBufferChannel> &channel) : mChannel(channel) {}
- virtual ~InputBufferClient() = default;
-
- virtual void onInputBufferAdded(size_t index, const sp<MediaCodecBuffer> &buffer) {
- std::shared_ptr<CCodecBufferChannel> channel = mChannel.lock();
- if (!channel) {
- return;
- }
- channel->mCallback->onInputBufferAvailable(index, buffer);
- }
-
- virtual void onStart() {
- // no-op
- }
-
- virtual void onStop() {
- // no-op
- }
-
- virtual void onRelease() {
- // no-op
- }
-
- virtual void onInputBufferAvailable(size_t index, const sp<MediaCodecBuffer> &buffer) {
- std::shared_ptr<CCodecBufferChannel> channel = mChannel.lock();
- if (!channel) {
- return;
- }
- channel->mCallback->onInputBufferAvailable(index, buffer);
- }
-
-protected:
- InputBufferClient() = default;
- std::weak_ptr<CCodecBufferChannel> mChannel;
-
- DISALLOW_EVIL_CONSTRUCTORS(InputBufferClient);
-};
-
class CCodecBufferChannel::OutputBuffers : public CCodecBufferChannel::Buffers {
public:
OutputBuffers() = default;
@@ -227,8 +177,6 @@
namespace {
-constexpr int32_t kMaskI32 = ~0;
-
// TODO: get this info from component
const static size_t kMinBufferArraySize = 16;
const static size_t kLinearBufferSize = 524288;
@@ -422,23 +370,8 @@
public:
GraphicInputBuffers() = default;
- bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
- *buffer = nullptr;
- for (size_t i = 0; i < mAvailable.size(); ++i) {
- if (mAvailable[i]) {
- *index = i;
- mAvailable[i] = false;
- return true;
- }
- }
- *index = mAvailable.size();
- mAvailable.push_back(false);
- return true;
- }
-
- std::shared_ptr<C2Buffer> releaseBufferIndex(size_t index) override {
- mAvailable[index] = true;
- return nullptr;
+ bool requestNewBuffer(size_t *, sp<MediaCodecBuffer> *) override {
+ return false;
}
std::shared_ptr<C2Buffer> releaseBuffer(const sp<MediaCodecBuffer> &) override {
@@ -452,8 +385,11 @@
return nullptr;
}
-private:
- std::vector<bool> mAvailable;
+ bool isArrayMode() const final { return true; }
+
+ void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
+ array->clear();
+ }
};
class OutputBuffersArray : public CCodecBufferChannel::OutputBuffers {
@@ -753,164 +689,8 @@
}
};
-class BufferQueueClient : public CCodecBufferChannel::InputBufferClient {
-public:
- explicit BufferQueueClient(const sp<GraphicBufferSource> &source) : mSource(source) {}
- virtual ~BufferQueueClient() = default;
-
- void onInputBufferAdded(size_t index, const sp<MediaCodecBuffer> &buffer) override {
- (void)buffer;
- mSource->onInputBufferAdded(index & kMaskI32);
- }
-
- void onStart() override {
- mSource->start();
- }
-
- void onStop() override {
- mSource->stop();
- }
-
- void onRelease() override {
- mSource->release();
- }
-
- void onInputBufferAvailable(size_t index, const sp<MediaCodecBuffer> &buffer) override {
- ALOGV("onInputBufferEmptied index = %zu", index);
- (void)buffer;
- // TODO: can we really ignore fence here?
- mSource->onInputBufferEmptied(index & kMaskI32, -1 /* fenceFd */);
- }
-
-private:
- sp<GraphicBufferSource> mSource;
-};
-
-class GraphicBlock : public C2GraphicBlock {
- using C2GraphicBlock::C2GraphicBlock;
- friend class ::android::CCodecBufferChannel;
-};
-
} // namespace
-class CCodecBufferChannel::C2ComponentWrapper : public ComponentWrapper {
-public:
- explicit C2ComponentWrapper(
- const std::shared_ptr<CCodecBufferChannel> &channel)
- : mChannel(channel), mLastTimestamp(0) {}
-
- virtual ~C2ComponentWrapper() {
- for (const std::pair<int32_t, C2Handle *> &entry : mHandles) {
- native_handle_delete(entry.second);
- }
- }
-
- status_t submitBuffer(
- int32_t bufferId, const sp<GraphicBuffer> &buffer,
- int64_t timestamp, int fenceFd) override {
- ALOGV("submitBuffer bufferId = %d", bufferId);
- // TODO: Use fd to construct fence
- (void)fenceFd;
-
- std::shared_ptr<CCodecBufferChannel> channel = mChannel.lock();
- if (!channel) {
- return NO_INIT;
- }
-
- std::shared_ptr<C2Allocator> allocator = mAllocator.lock();
- if (!allocator) {
- c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
- C2PlatformAllocatorStore::GRALLOC,
- &allocator);
- if (err != OK) {
- return UNKNOWN_ERROR;
- }
- mAllocator = allocator;
- }
-
- std::shared_ptr<C2GraphicAllocation> alloc;
- C2Handle *handle = WrapNativeCodec2GrallocHandle(
- buffer->handle, buffer->width, buffer->height,
- buffer->format, buffer->usage, buffer->stride);
- c2_status_t err = allocator->priorGraphicAllocation(handle, &alloc);
- if (err != OK) {
- return UNKNOWN_ERROR;
- }
-
- std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
-
- std::unique_ptr<C2Work> work(new C2Work);
- work->input.flags = (C2FrameData::flags_t)0;
- work->input.ordinal.timestamp = timestamp;
- work->input.ordinal.frameIndex = channel->mFrameIndex++;
- work->input.buffers.clear();
- work->input.buffers.emplace_back(new Buffer2D(
- // TODO: fence
- block->share(C2Rect(block->width(), block->height()), ::android::C2Fence())));
- work->worklets.clear();
- work->worklets.emplace_back(new C2Worklet);
- std::list<std::unique_ptr<C2Work>> items;
- items.push_back(std::move(work));
-
- err = channel->mComponent->queue_nb(&items);
- if (err != OK) {
- native_handle_delete(handle);
- return UNKNOWN_ERROR;
- }
-
- mLastTimestamp = timestamp;
- if (mHandles.count(bufferId) > 0) {
- native_handle_delete(mHandles[bufferId]);
- }
- mHandles[bufferId] = handle;
-
- Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(channel->mInputBuffers);
- ALOGV("releaseBufferIndex index = %d", bufferId);
- (*buffers)->releaseBufferIndex(bufferId);
-
- return OK;
- }
-
- status_t submitEos(int32_t bufferId) override {
- std::shared_ptr<CCodecBufferChannel> channel = mChannel.lock();
- if (!channel) {
- return NO_INIT;
- }
-
- std::unique_ptr<C2Work> work(new C2Work);
- work->input.flags = C2FrameData::FLAG_END_OF_STREAM;
- work->input.ordinal.timestamp = mLastTimestamp;
- work->input.ordinal.frameIndex = channel->mFrameIndex++;
- work->input.buffers.clear();
- work->input.buffers.push_back(nullptr);
- work->worklets.clear();
- work->worklets.emplace_back(new C2Worklet);
- std::list<std::unique_ptr<C2Work>> items;
- items.push_back(std::move(work));
-
- c2_status_t err = channel->mComponent->queue_nb(&items);
-
- Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(channel->mInputBuffers);
- (*buffers)->releaseBufferIndex(bufferId);
-
- return (err == C2_OK) ? OK : UNKNOWN_ERROR;
- }
-
- void dispatchDataSpaceChanged(
- int32_t dataSpace, int32_t aspects, int32_t pixelFormat) override {
- // TODO
- (void)dataSpace;
- (void)aspects;
- (void)pixelFormat;
- }
-
-private:
- std::weak_ptr<CCodecBufferChannel> mChannel;
- std::map<int32_t, C2Handle *> mHandles;
- int64_t mLastTimestamp;
- std::weak_ptr<C2Allocator> mAllocator;
-};
-
CCodecBufferChannel::QueueGuard::QueueGuard(
CCodecBufferChannel::QueueSync &sync) : mSync(sync) {
std::unique_lock<std::mutex> l(mSync.mMutex);
@@ -967,13 +747,10 @@
if (mCrypto != nullptr && mDealer != nullptr && mHeapSeqNum >= 0) {
mCrypto->unsetHeap(mHeapSeqNum);
}
- // TODO: is this the right place?
- mInputClient->onRelease();
}
void CCodecBufferChannel::setComponent(const std::shared_ptr<C2Component> &component) {
mComponent = component;
- mInputClient.reset(new InputBufferClient(shared_from_this()));
C2StreamFormatConfig::input inputFormat(0u);
C2StreamFormatConfig::output outputFormat(0u);
@@ -1026,16 +803,11 @@
}
}
-status_t CCodecBufferChannel::setGraphicBufferSource(
- const sp<GraphicBufferSource> &source) {
- ALOGV("setGraphicBufferSource");
- mInputClient.reset(new BufferQueueClient(source));
-
- // TODO: proper color aspect & dataspace
- android_dataspace dataSpace = HAL_DATASPACE_BT709;
- // TODO: read settings properly from the interface
- return source->configure(new C2ComponentWrapper(
- shared_from_this()), dataSpace, 16, 1080, 1920, GRALLOC_USAGE_SW_READ_OFTEN);
+status_t CCodecBufferChannel::setInputSurface(
+ const std::shared_ptr<InputSurfaceWrapper> &surface) {
+ ALOGV("setInputSurface");
+ mInputSurface = surface;
+ return OK;
}
status_t CCodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
@@ -1100,12 +872,13 @@
{
Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
if (!(*buffers)->requestNewBuffer(&index, &inBuffer)) {
- ALOGW("no new buffer available");
+ ALOGV("no new buffer available");
inBuffer = nullptr;
+ return;
}
}
ALOGV("new input index = %zu", index);
- mInputClient->onInputBufferAvailable(index, inBuffer);
+ mCallback->onInputBufferAvailable(index, inBuffer);
}
status_t CCodecBufferChannel::renderOutputBuffer(
@@ -1182,7 +955,9 @@
{
Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
if((*buffers)->releaseBuffer(buffer)) {
+ buffers.unlock();
feedInputBufferIfAvailable();
+ buffers.lock();
}
}
return OK;
@@ -1221,29 +996,38 @@
}
mSync.start();
- // TODO: use proper buffer depth instead of this random value
- for (size_t i = 0; i < kMinBufferArraySize; ++i) {
- size_t index;
- sp<MediaCodecBuffer> buffer;
- {
- Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
- if (!(*buffers)->requestNewBuffer(&index, &buffer)) {
- buffers.unlock();
- ALOGE("start: cannot allocate memory");
- mOnError(NO_MEMORY, ACTION_CODE_FATAL);
- buffers.lock();
- return;
+ if (mInputSurface == nullptr) {
+ // TODO: use proper buffer depth instead of this random value
+ for (size_t i = 0; i < kMinBufferArraySize; ++i) {
+ size_t index;
+ sp<MediaCodecBuffer> buffer;
+ {
+ Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
+ if (!(*buffers)->requestNewBuffer(&index, &buffer)) {
+ if (i == 0) {
+ ALOGE("start: cannot allocate memory at all");
+ buffers.unlock();
+ mOnError(NO_MEMORY, ACTION_CODE_FATAL);
+ buffers.lock();
+ } else {
+ ALOGV("start: cannot allocate memory, only %zu buffers allocated", i);
+ }
+ break;
+ }
}
+ mCallback->onInputBufferAvailable(index, buffer);
}
- mInputClient->onInputBufferAdded(index, buffer);
+ } else {
+ (void)mInputSurface->connect(mComponent);
}
- mInputClient->onStart();
}
void CCodecBufferChannel::stop() {
mSync.stop();
mFirstValidFrameIndex = mFrameIndex.load();
- mInputClient->onStop();
+ if (mInputSurface != nullptr) {
+ mInputSurface->disconnect();
+ }
}
void CCodecBufferChannel::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
diff --git a/media/libstagefright/CallbackMediaSource.cpp b/media/libstagefright/CallbackMediaSource.cpp
index 6811882..ea7392e 100644
--- a/media/libstagefright/CallbackMediaSource.cpp
+++ b/media/libstagefright/CallbackMediaSource.cpp
@@ -36,7 +36,7 @@
return mSource->getFormat();
}
-status_t CallbackMediaSource::read(MediaBuffer **buffer, const ReadOptions *options) {
+status_t CallbackMediaSource::read(MediaBufferBase **buffer, const ReadOptions *options) {
return mSource->read(buffer, reinterpret_cast<const ReadOptions*>(options));
}
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 6ed0d0e..4960418 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -1040,7 +1040,7 @@
releaseRecordingFrame(frame);
}
-void CameraSource::signalBufferReturned(MediaBuffer *buffer) {
+void CameraSource::signalBufferReturned(MediaBufferBase *buffer) {
ALOGV("signalBufferReturned: %p", buffer->data());
Mutex::Autolock autoLock(mLock);
for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin();
@@ -1059,7 +1059,7 @@
}
status_t CameraSource::read(
- MediaBuffer **buffer, const ReadOptions *options) {
+ MediaBufferBase **buffer, const ReadOptions *options) {
ALOGV("read");
*buffer = NULL;
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 970526a..f3f06d8 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -168,7 +168,7 @@
return isSuccessful;
}
-void CameraSourceTimeLapse::signalBufferReturned(MediaBuffer* buffer) {
+void CameraSourceTimeLapse::signalBufferReturned(MediaBufferBase* buffer) {
ALOGV("signalBufferReturned");
Mutex::Autolock autoLock(mQuickStopLock);
if (mQuickStop && (buffer == mLastReadBufferCopy)) {
@@ -180,9 +180,9 @@
}
void createMediaBufferCopy(
- const MediaBuffer& sourceBuffer,
+ const MediaBufferBase& sourceBuffer,
int64_t frameTime,
- MediaBuffer **newBuffer) {
+ MediaBufferBase **newBuffer) {
ALOGV("createMediaBufferCopy");
size_t sourceSize = sourceBuffer.size();
@@ -194,7 +194,7 @@
(*newBuffer)->meta_data()->setInt64(kKeyTime, frameTime);
}
-void CameraSourceTimeLapse::fillLastReadBufferCopy(MediaBuffer& sourceBuffer) {
+void CameraSourceTimeLapse::fillLastReadBufferCopy(MediaBufferBase& sourceBuffer) {
ALOGV("fillLastReadBufferCopy");
int64_t frameTime;
CHECK(sourceBuffer.meta_data()->findInt64(kKeyTime, &frameTime));
@@ -204,7 +204,7 @@
}
status_t CameraSourceTimeLapse::read(
- MediaBuffer **buffer, const ReadOptions *options) {
+ MediaBufferBase **buffer, const ReadOptions *options) {
ALOGV("read");
if (mLastReadBufferCopy == NULL) {
mLastReadStatus = CameraSource::read(buffer, options);
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index b529940..6f88c0e 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -230,7 +230,7 @@
}
codecBuffer = inputBuffers[inputIndex];
- MediaBuffer *mediaBuffer = NULL;
+ MediaBufferBase *mediaBuffer = NULL;
err = mSource->read(&mediaBuffer, &options);
options.clearSeekTo();
diff --git a/media/libstagefright/JPEGSource.cpp b/media/libstagefright/JPEGSource.cpp
index ee3aedb..10eb2d2 100644
--- a/media/libstagefright/JPEGSource.cpp
+++ b/media/libstagefright/JPEGSource.cpp
@@ -21,6 +21,7 @@
#include <media/DataSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/JPEGSource.h>
+#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
@@ -108,7 +109,7 @@
}
status_t JPEGSource::read(
- MediaBuffer **out, const ReadOptions *options) {
+ MediaBufferBase **out, const ReadOptions *options) {
*out = NULL;
int64_t seekTimeUs;
@@ -117,7 +118,7 @@
return UNKNOWN_ERROR;
}
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
mGroup->acquire_buffer(&buffer);
ssize_t n = mSource->readAt(mOffset, buffer->data(), mSize - mOffset);
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index 4c85b0d..cdcd657 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -85,8 +85,8 @@
void extractCodecSpecificData();
- void appendAACFrames(MediaBuffer *buffer);
- void appendAVCFrame(MediaBuffer *buffer);
+ void appendAACFrames(MediaBufferBase *buffer);
+ void appendAVCFrame(MediaBufferBase *buffer);
DISALLOW_EVIL_CONSTRUCTORS(SourceInfo);
};
@@ -249,7 +249,7 @@
notify->post();
}
-void MPEG2TSWriter::SourceInfo::appendAVCFrame(MediaBuffer *buffer) {
+void MPEG2TSWriter::SourceInfo::appendAVCFrame(MediaBufferBase *buffer) {
sp<AMessage> notify = mNotify->dup();
notify->setInt32("what", kNotifyBuffer);
@@ -279,7 +279,7 @@
notify->post();
}
-void MPEG2TSWriter::SourceInfo::appendAACFrames(MediaBuffer *buffer) {
+void MPEG2TSWriter::SourceInfo::appendAACFrames(MediaBufferBase *buffer) {
sp<AMessage> notify = mNotify->dup();
notify->setInt32("what", kNotifyBuffer);
@@ -368,7 +368,7 @@
case kWhatRead:
{
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
status_t err = mSource->read(&buffer);
if (err != OK && err != INFO_FORMAT_CHANGED) {
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 8db00f0..387cb13 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -2809,7 +2809,7 @@
sp<MetaData> meta_data;
status_t err = OK;
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
const char *trackName = getTrackType();
while (!mDone && (err = mSource->read(&buffer)) == OK) {
if (buffer->range_length() == 0) {
diff --git a/media/libstagefright/MediaAdapter.cpp b/media/libstagefright/MediaAdapter.cpp
index 74eb1ff..f1b6e8c 100644
--- a/media/libstagefright/MediaAdapter.cpp
+++ b/media/libstagefright/MediaAdapter.cpp
@@ -72,7 +72,7 @@
return mOutputFormat;
}
-void MediaAdapter::signalBufferReturned(MediaBuffer *buffer) {
+void MediaAdapter::signalBufferReturned(MediaBufferBase *buffer) {
Mutex::Autolock autoLock(mAdapterLock);
CHECK(buffer != NULL);
buffer->setObserver(0);
@@ -82,7 +82,7 @@
}
status_t MediaAdapter::read(
- MediaBuffer **buffer, const ReadOptions * /* options */) {
+ MediaBufferBase **buffer, const ReadOptions * /* options */) {
Mutex::Autolock autoLock(mAdapterLock);
if (!mStarted) {
ALOGV("Read before even started!");
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 04d83af..08331ad 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -59,7 +59,7 @@
void pause();
void resume();
status_t setStopTimeUs(int64_t stopTimeUs);
- bool readBuffer(MediaBuffer **buffer);
+ bool readBuffer(MediaBufferBase **buffer);
protected:
virtual void onMessageReceived(const sp<AMessage> &msg);
@@ -86,14 +86,14 @@
int64_t mReadPendingSince;
bool mPaused;
bool mPulling;
- Vector<MediaBuffer *> mReadBuffers;
+ Vector<MediaBufferBase *> mReadBuffers;
void flush();
// if queue is empty, return false and set *|buffer| to NULL . Otherwise, pop
// buffer from front of the queue, place it into *|buffer| and return true.
- bool readBuffer(MediaBuffer **buffer);
+ bool readBuffer(MediaBufferBase **buffer);
// add a buffer to the back of the queue
- void pushBuffer(MediaBuffer *mbuf);
+ void pushBuffer(MediaBufferBase *mbuf);
};
Mutexed<Queue> mQueue;
@@ -123,11 +123,11 @@
mLooper->stop();
}
-void MediaCodecSource::Puller::Queue::pushBuffer(MediaBuffer *mbuf) {
+void MediaCodecSource::Puller::Queue::pushBuffer(MediaBufferBase *mbuf) {
mReadBuffers.push_back(mbuf);
}
-bool MediaCodecSource::Puller::Queue::readBuffer(MediaBuffer **mbuf) {
+bool MediaCodecSource::Puller::Queue::readBuffer(MediaBufferBase **mbuf) {
if (mReadBuffers.empty()) {
*mbuf = NULL;
return false;
@@ -138,14 +138,14 @@
}
void MediaCodecSource::Puller::Queue::flush() {
- MediaBuffer *mbuf;
+ MediaBufferBase *mbuf;
while (readBuffer(&mbuf)) {
// there are no null buffers in the queue
mbuf->release();
}
}
-bool MediaCodecSource::Puller::readBuffer(MediaBuffer **mbuf) {
+bool MediaCodecSource::Puller::readBuffer(MediaBufferBase **mbuf) {
Mutexed<Queue>::Locked queue(mQueue);
return queue->readBuffer(mbuf);
}
@@ -298,7 +298,7 @@
}
queue.unlock();
- MediaBuffer *mbuf = NULL;
+ MediaBufferBase *mbuf = NULL;
status_t err = mSource->read(&mbuf);
queue.lock();
@@ -413,7 +413,7 @@
}
status_t MediaCodecSource::read(
- MediaBuffer** buffer, const ReadOptions* /* options */) {
+ MediaBufferBase** buffer, const ReadOptions* /* options */) {
Mutexed<Output>::Locked output(mOutput);
*buffer = NULL;
@@ -428,7 +428,7 @@
return output->mErrorCode;
}
-void MediaCodecSource::signalBufferReturned(MediaBuffer *buffer) {
+void MediaCodecSource::signalBufferReturned(MediaBufferBase *buffer) {
buffer->setObserver(0);
buffer->release();
}
@@ -636,7 +636,7 @@
if (!reachedEOS) {
ALOGV("encoder (%s) reached EOS", mIsVideo ? "video" : "audio");
// release all unread media buffers
- for (List<MediaBuffer*>::iterator it = output->mBufferQueue.begin();
+ for (List<MediaBufferBase*>::iterator it = output->mBufferQueue.begin();
it != output->mBufferQueue.end(); it++) {
(*it)->release();
}
@@ -682,7 +682,7 @@
}
status_t MediaCodecSource::feedEncoderInputBuffers() {
- MediaBuffer* mbuf = NULL;
+ MediaBufferBase* mbuf = NULL;
while (!mAvailEncoderInputIndices.empty() && mPuller->readBuffer(&mbuf)) {
size_t bufferIndex = *mAvailEncoderInputIndices.begin();
mAvailEncoderInputIndices.erase(mAvailEncoderInputIndices.begin());
@@ -906,7 +906,7 @@
break;
}
- MediaBuffer *mbuf = new MediaBuffer(outbuf->size());
+ MediaBufferBase *mbuf = new MediaBuffer(outbuf->size());
mbuf->setObserver(this);
mbuf->add_ref();
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index bb72167..543c274 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -112,23 +112,25 @@
// initialize source decryption if needed
source->DrmInitialization(nullptr /* mime */);
- sp<AMessage> meta;
-
+ void *meta = nullptr;
MediaExtractor::CreatorFunc creator = NULL;
- String8 tmp;
+ MediaExtractor::FreeMetaFunc freeMeta = nullptr;
float confidence;
sp<ExtractorPlugin> plugin;
- creator = sniff(source.get(), &tmp, &confidence, &meta, plugin);
+ creator = sniff(source.get(), &confidence, &meta, &freeMeta, plugin);
if (!creator) {
ALOGV("FAILED to autodetect media content.");
return NULL;
}
- mime = tmp.string();
- ALOGV("Autodetected media content as '%s' with confidence %.2f",
- mime, confidence);
-
MediaExtractor *ret = creator(source.get(), meta);
+ if (meta != nullptr && freeMeta != nullptr) {
+ freeMeta(meta);
+ }
+
+ ALOGV("Created an extractor '%s' with confidence %.2f",
+ ret != nullptr ? ret->name() : "<null>", confidence);
+
return CreateIMediaExtractorFromMediaExtractor(ret, source, plugin);
}
@@ -165,11 +167,10 @@
// static
MediaExtractor::CreatorFunc MediaExtractorFactory::sniff(
- DataSourceBase *source, String8 *mimeType, float *confidence, sp<AMessage> *meta,
- sp<ExtractorPlugin> &plugin) {
- *mimeType = "";
+ DataSourceBase *source, float *confidence, void **meta,
+ MediaExtractor::FreeMetaFunc *freeMeta, sp<ExtractorPlugin> &plugin) {
*confidence = 0.0f;
- meta->clear();
+ *meta = nullptr;
std::shared_ptr<List<sp<ExtractorPlugin>>> plugins;
{
@@ -183,16 +184,23 @@
MediaExtractor::CreatorFunc curCreator = NULL;
MediaExtractor::CreatorFunc bestCreator = NULL;
for (auto it = plugins->begin(); it != plugins->end(); ++it) {
- String8 newMimeType;
float newConfidence;
- sp<AMessage> newMeta;
- if ((curCreator = (*it)->def.sniff(source, &newMimeType, &newConfidence, &newMeta))) {
+ void *newMeta = nullptr;
+ MediaExtractor::FreeMetaFunc newFreeMeta = nullptr;
+ if ((curCreator = (*it)->def.sniff(source, &newConfidence, &newMeta, &newFreeMeta))) {
if (newConfidence > *confidence) {
- *mimeType = newMimeType;
*confidence = newConfidence;
+ if (*meta != nullptr && *freeMeta != nullptr) {
+ (*freeMeta)(*meta);
+ }
*meta = newMeta;
+ *freeMeta = newFreeMeta;
plugin = *it;
bestCreator = curCreator;
+ } else {
+ if (newMeta != nullptr && newFreeMeta != nullptr) {
+ newFreeMeta(newMeta);
+ }
}
}
}
diff --git a/media/libstagefright/MetaDataUtils.cpp b/media/libstagefright/MetaDataUtils.cpp
index fd51a2c..ac1f33f 100644
--- a/media/libstagefright/MetaDataUtils.cpp
+++ b/media/libstagefright/MetaDataUtils.cpp
@@ -49,20 +49,56 @@
sp<MetaData> MakeAACCodecSpecificData(
unsigned profile, unsigned sampling_freq_index,
unsigned channel_configuration) {
- int32_t sampleRate;
- int32_t channelCount;
- sp<ABuffer> csd = MakeAACCodecSpecificData(profile, sampling_freq_index,
- channel_configuration, &sampleRate, &channelCount);
- if (csd == nullptr) {
+ if(sampling_freq_index > 11u) {
return nullptr;
}
+ int32_t sampleRate;
+ int32_t channelCount;
+ static const int32_t kSamplingFreq[] = {
+ 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+ 16000, 12000, 11025, 8000
+ };
+ sampleRate = kSamplingFreq[sampling_freq_index];
+ channelCount = channel_configuration;
+
+ static const uint8_t kStaticESDS[] = {
+ 0x03, 22,
+ 0x00, 0x00, // ES_ID
+ 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag
+
+ 0x04, 17,
+ 0x40, // Audio ISO/IEC 14496-3
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+
+ 0x05, 2,
+ // AudioSpecificInfo follows
+
+ // oooo offf fccc c000
+ // o - audioObjectType
+ // f - samplingFreqIndex
+ // c - channelConfig
+ };
+
+ size_t csdSize = sizeof(kStaticESDS) + 2;
+ uint8_t *csd = new uint8_t[csdSize];
+ memcpy(csd, kStaticESDS, sizeof(kStaticESDS));
+
+ csd[sizeof(kStaticESDS)] =
+ ((profile + 1) << 3) | (sampling_freq_index >> 1);
+
+ csd[sizeof(kStaticESDS) + 1] =
+ ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
+
sp<MetaData> meta = new MetaData;
meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
meta->setInt32(kKeySampleRate, sampleRate);
meta->setInt32(kKeyChannelCount, channelCount);
- meta->setData(kKeyESDS, 0, csd->data(), csd->size());
+ meta->setData(kKeyESDS, 0, csd, csdSize);
+ delete [] csd;
return meta;
}
diff --git a/media/libstagefright/NdkUtils.cpp b/media/libstagefright/NdkUtils.cpp
new file mode 100644
index 0000000..904fe72
--- /dev/null
+++ b/media/libstagefright/NdkUtils.cpp
@@ -0,0 +1,33 @@
+/*
+ * 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
+
+#include <media/stagefright/NdkUtils.h>
+#include <media/stagefright/Utils.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+namespace android {
+
+sp<MetaData> convertMediaFormatWrapperToMetaData(const sp<AMediaFormatWrapper> &fmt) {
+ sp<AMessage> msg = fmt->toAMessage();
+ sp<MetaData> meta = new MetaData;
+ convertMessageToMetaData(msg, meta);
+ return meta;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index d96f7e0..c6cbb2f 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -45,7 +45,7 @@
mSampleTimeUs(-1ll) {
}
-NuMediaExtractor::Sample::Sample(MediaBuffer *buffer, int64_t timeUs)
+NuMediaExtractor::Sample::Sample(MediaBufferBase *buffer, int64_t timeUs)
: mBuffer(buffer),
mSampleTimeUs(timeUs) {
}
@@ -488,12 +488,12 @@
}
status_t err = OK;
- Vector<MediaBuffer *> mediaBuffers;
+ Vector<MediaBufferBase *> mediaBuffers;
if (info->mSource->supportReadMultiple()) {
options.setNonBlocking();
err = info->mSource->readMultiple(&mediaBuffers, info->mMaxFetchCount, &options);
} else {
- MediaBuffer *mbuf = NULL;
+ MediaBufferBase *mbuf = NULL;
err = info->mSource->read(&mbuf, &options);
if (err == OK && mbuf != NULL) {
mediaBuffers.push_back(mbuf);
@@ -505,7 +505,7 @@
ALOGW("read on track %zu failed with error %d", info->mTrackIndex, err);
size_t count = mediaBuffers.size();
for (size_t id = 0; id < count; ++id) {
- MediaBuffer *mbuf = mediaBuffers[id];
+ MediaBufferBase *mbuf = mediaBuffers[id];
if (mbuf != NULL) {
mbuf->release();
}
@@ -517,7 +517,7 @@
bool releaseRemaining = false;
for (size_t id = 0; id < count; ++id) {
int64_t timeUs;
- MediaBuffer *mbuf = mediaBuffers[id];
+ MediaBufferBase *mbuf = mediaBuffers[id];
if (mbuf == NULL) {
continue;
}
@@ -565,7 +565,8 @@
return OK;
}
-status_t NuMediaExtractor::appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer) {
+status_t NuMediaExtractor::appendVorbisNumPageSamples(
+ MediaBufferBase *mbuf, const sp<ABuffer> &buffer) {
int32_t numPageSamples;
if (!mbuf->meta_data()->findInt32(
kKeyValidSamples, &numPageSamples)) {
diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp
index 5bb0953..7efb91c 100644
--- a/media/libstagefright/RemoteMediaExtractor.cpp
+++ b/media/libstagefright/RemoteMediaExtractor.cpp
@@ -121,14 +121,6 @@
return mExtractor->flags();
}
-char* RemoteMediaExtractor::getDrmTrackInfo(size_t trackID, int * len) {
- return mExtractor->getDrmTrackInfo(trackID, len);
-}
-
-void RemoteMediaExtractor::setUID(uid_t uid) {
- return mExtractor->setUID(uid);
-}
-
status_t RemoteMediaExtractor::setMediaCas(const HInterfaceToken &casToken) {
return mExtractor->setMediaCas((uint8_t*)casToken.data(), casToken.size());
}
diff --git a/media/libstagefright/RemoteMediaSource.cpp b/media/libstagefright/RemoteMediaSource.cpp
index 6b48ce8..d038454 100644
--- a/media/libstagefright/RemoteMediaSource.cpp
+++ b/media/libstagefright/RemoteMediaSource.cpp
@@ -45,7 +45,8 @@
return mSource->getFormat();
}
-status_t RemoteMediaSource::read(MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
+status_t RemoteMediaSource::read(
+ MediaBufferBase **buffer, const MediaSource::ReadOptions *options) {
return mSource->read(buffer, reinterpret_cast<const MediaSource::ReadOptions*>(options));
}
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
index 9b2fb4f..f93a0b7 100644
--- a/media/libstagefright/SimpleDecodingSource.cpp
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -200,7 +200,7 @@
}
status_t SimpleDecodingSource::read(
- MediaBuffer **buffer, const ReadOptions *options) {
+ MediaBufferBase **buffer, const ReadOptions *options) {
*buffer = NULL;
Mutexed<ProtectedState>::Locked me(mProtectedState);
@@ -221,7 +221,7 @@
}
status_t SimpleDecodingSource::doRead(
- Mutexed<ProtectedState>::Locked &me, MediaBuffer **buffer, const ReadOptions *options) {
+ Mutexed<ProtectedState>::Locked &me, MediaBufferBase **buffer, const ReadOptions *options) {
// |me| is always locked on entry, but is allowed to be unlocked on exit
CHECK_EQ(me->mState, STARTED);
@@ -267,7 +267,7 @@
return UNKNOWN_ERROR;
}
- MediaBuffer *in_buf;
+ MediaBufferBase *in_buf;
while (true) {
in_buf = NULL;
me.unlock();
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index d14e86b..4b3076a 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -251,7 +251,7 @@
// Pass the data to the MediaBuffer. Pass in only the metadata
// Note: Call only when you have the lock
-void SurfaceMediaSource::passMetadataBuffer_l(MediaBuffer **buffer,
+void SurfaceMediaSource::passMetadataBuffer_l(MediaBufferBase **buffer,
ANativeWindowBuffer *bufferHandle) const {
*buffer = new MediaBuffer(sizeof(VideoNativeMetadata));
VideoNativeMetadata *data = (VideoNativeMetadata *)(*buffer)->data();
@@ -267,7 +267,7 @@
}
status_t SurfaceMediaSource::read(
- MediaBuffer **buffer, const ReadOptions * /* options */) {
+ MediaBufferBase **buffer, const ReadOptions * /* options */) {
ALOGV("read");
Mutex::Autolock lock(mMutex);
@@ -371,7 +371,7 @@
return OK;
}
-static buffer_handle_t getMediaBufferHandle(MediaBuffer *buffer) {
+static buffer_handle_t getMediaBufferHandle(MediaBufferBase *buffer) {
// need to convert to char* for pointer arithmetic and then
// copy the byte stream into our handle
buffer_handle_t bufferHandle;
@@ -379,7 +379,7 @@
return bufferHandle;
}
-void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) {
+void SurfaceMediaSource::signalBufferReturned(MediaBufferBase *buffer) {
ALOGV("signalBufferReturned");
bool foundBuffer = false;
diff --git a/media/libstagefright/bqhelper/Android.bp b/media/libstagefright/bqhelper/Android.bp
index b5b4a2a..388ed6b 100644
--- a/media/libstagefright/bqhelper/Android.bp
+++ b/media/libstagefright/bqhelper/Android.bp
@@ -43,6 +43,7 @@
export_shared_lib_headers: [
"libstagefright_foundation",
+ "libhidlmemory",
],
cflags: [
diff --git a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/WGraphicBufferProducer.h b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/WGraphicBufferProducer.h
index 6f594fd..8ddf20f 100644
--- a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/WGraphicBufferProducer.h
+++ b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/WGraphicBufferProducer.h
@@ -20,7 +20,6 @@
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
-#include <android-base/logging.h>
#include <binder/Binder.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
@@ -52,6 +51,15 @@
typedef ::android::IProducerListener BProducerListener;
using ::android::BnGraphicBufferProducer;
+#ifndef LOG
+struct LOG_dummy {
+ template <typename T>
+ LOG_dummy& operator<< (const T&) { return *this; }
+};
+
+#define LOG(x) LOG_dummy()
+#endif
+
// Instantiate only if HGraphicBufferProducer is base of BASE.
template <typename BASE,
typename = typename std::enable_if<std::is_base_of<HGraphicBufferProducer, BASE>::value>::type>
diff --git a/media/libstagefright/codec2/1.0/Android.bp b/media/libstagefright/codec2/1.0/Android.bp
new file mode 100644
index 0000000..84d301a
--- /dev/null
+++ b/media/libstagefright/codec2/1.0/Android.bp
@@ -0,0 +1,43 @@
+cc_library_shared {
+ name: "android.hardware.media.c2@1.0-service-impl",
+ // relative_install_path: "hw",
+ // TODO: vendor: true,
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+
+ srcs: [
+ //"ComponentAuth.cpp",
+ //"Component.cpp",
+ //"ComponentListener.cpp",
+ //"ComponentStore.cpp",
+ //"Configurable.cpp",
+ "InputSurface.cpp",
+ "InputSurfaceConnection.cpp",
+ //"types.cpp",
+ ],
+
+ include_dirs: [
+ "frameworks/av/media/libstagefright/codec2/include",
+ "frameworks/av/media/libstagefright/codec2/vndk/internal",
+ ],
+
+ shared_libs: [
+ "libcutils",
+ "libgui",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libnativewindow",
+ "libstagefright_bufferqueue_helper",
+ "libstagefright_codec2_vndk",
+ "libui",
+ "libutils",
+
+ //"android.hardware.media.c2@1.0",
+ "android.hardware.graphics.bufferqueue@1.0",
+ "android.hidl.token@1.0-utils",
+ ],
+}
+
diff --git a/media/libstagefright/codec2/1.0/InputSurface.cpp b/media/libstagefright/codec2/1.0/InputSurface.cpp
new file mode 100644
index 0000000..977d410
--- /dev/null
+++ b/media/libstagefright/codec2/1.0/InputSurface.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright 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 "InputSurface"
+#include <utils/Log.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2PlatformSupport.h>
+
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
+#include <media/stagefright/codec2/1.0/InputSurface.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::GraphicBufferSource;
+
+sp<InputSurface> InputSurface::Create() {
+ sp<GraphicBufferSource> source = new GraphicBufferSource;
+ if (source->initCheck() != OK) {
+ return nullptr;
+ }
+ return new InputSurface(source->getIGraphicBufferProducer(), source);
+}
+
+InputSurface::InputSurface(
+ const sp<BGraphicBufferProducer> &base, const sp<GraphicBufferSource> &source)
+ : InputSurfaceBase(base),
+ mSource(source) {
+}
+
+sp<InputSurfaceConnection> InputSurface::connectToComponent(
+ const std::shared_ptr<C2Component> &comp) {
+ sp<InputSurfaceConnection> conn = new InputSurfaceConnection(mSource, comp);
+ if (!conn->init()) {
+ return nullptr;
+ }
+ return conn;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
diff --git a/media/libstagefright/codec2/1.0/InputSurfaceConnection.cpp b/media/libstagefright/codec2/1.0/InputSurfaceConnection.cpp
new file mode 100644
index 0000000..32d6404
--- /dev/null
+++ b/media/libstagefright/codec2/1.0/InputSurfaceConnection.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright 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 "InputSurfaceConnection"
+#include <utils/Log.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2BlockInternal.h>
+#include <C2PlatformSupport.h>
+
+#include <gui/Surface.h>
+#include <media/stagefright/codec2/1.0/InputSurfaceConnection.h>
+#include <system/window.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::status_t;
+
+namespace {
+
+class Buffer2D : public C2Buffer {
+public:
+ explicit Buffer2D(C2ConstGraphicBlock block) : C2Buffer({ block }) {}
+};
+
+} // namespace
+
+constexpr int32_t kBufferCount = 16;
+
+class InputSurfaceConnection::Impl : public ComponentWrapper {
+public:
+ Impl(const sp<GraphicBufferSource> &source, const std::shared_ptr<C2Component> &comp)
+ : mSource(source), mComp(comp) {
+ }
+
+ virtual ~Impl() = default;
+
+ bool init() {
+ sp<GraphicBufferSource> source = mSource.promote();
+ if (source == nullptr) {
+ return false;
+ }
+ status_t err = source->initCheck();
+ if (err != OK) {
+ ALOGE("Impl::init: GBS init failed: %d", err);
+ return false;
+ }
+ // TODO: proper color aspect & dataspace
+ android_dataspace dataSpace = HAL_DATASPACE_BT709;
+ // TODO: read settings properly from the interface
+ err = source->configure(
+ this, dataSpace, kBufferCount, 1080, 1920, GRALLOC_USAGE_SW_READ_OFTEN);
+ if (err != OK) {
+ ALOGE("Impl::init: GBS configure failed: %d", err);
+ return false;
+ }
+ for (int32_t i = 0; i < kBufferCount; ++i) {
+ if (!source->onInputBufferAdded(i).isOk()) {
+ ALOGE("Impl::init: population GBS slots failed");
+ return false;
+ }
+ }
+ if (!source->start().isOk()) {
+ ALOGE("Impl::init: GBS start failed");
+ return false;
+ }
+ c2_status_t c2err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
+ C2AllocatorStore::PLATFORM_START + 1, // GRALLOC
+ &mAllocator);
+ if (c2err != OK) {
+ ALOGE("Impl::init: failed to fetch gralloc allocator: %d", c2err);
+ return false;
+ }
+ return true;
+ }
+
+ // From ComponentWrapper
+ status_t submitBuffer(
+ int32_t bufferId, const sp<GraphicBuffer> &buffer,
+ int64_t timestamp, int fenceFd) override {
+ ALOGV("Impl::submitBuffer bufferId = %d", bufferId);
+ // TODO: Use fd to construct fence
+ (void)fenceFd;
+
+ std::shared_ptr<C2Component> comp = mComp.lock();
+ if (!comp) {
+ return NO_INIT;
+ }
+
+ std::shared_ptr<C2GraphicAllocation> alloc;
+ C2Handle *handle = WrapNativeCodec2GrallocHandle(
+ buffer->handle, buffer->width, buffer->height,
+ buffer->format, buffer->usage, buffer->stride);
+ c2_status_t err = mAllocator->priorGraphicAllocation(handle, &alloc);
+ if (err != OK) {
+ return UNKNOWN_ERROR;
+ }
+ std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
+
+ std::unique_ptr<C2Work> work(new C2Work);
+ work->input.flags = (C2FrameData::flags_t)0;
+ work->input.ordinal.timestamp = timestamp;
+ work->input.ordinal.frameIndex = mFrameIndex++;
+ work->input.buffers.clear();
+ std::shared_ptr<C2Buffer> c2Buffer(
+ // TODO: fence
+ new Buffer2D(block->share(
+ C2Rect(block->width(), block->height()), ::android::C2Fence())),
+ [handle, bufferId, src = mSource](C2Buffer *ptr) {
+ delete ptr;
+ native_handle_delete(handle);
+ sp<GraphicBufferSource> source = src.promote();
+ if (source != nullptr) {
+ // TODO: fence
+ (void)source->onInputBufferEmptied(bufferId, -1);
+ }
+ });
+ work->input.buffers.push_back(c2Buffer);
+ work->worklets.clear();
+ work->worklets.emplace_back(new C2Worklet);
+ std::list<std::unique_ptr<C2Work>> items;
+ items.push_back(std::move(work));
+
+ err = comp->queue_nb(&items);
+ if (err != C2_OK) {
+ return UNKNOWN_ERROR;
+ }
+
+ mLastTimestamp = timestamp;
+
+ return OK;
+ }
+
+ status_t submitEos(int32_t) override {
+ std::shared_ptr<C2Component> comp = mComp.lock();
+ if (!comp) {
+ return NO_INIT;
+ }
+
+ std::unique_ptr<C2Work> work(new C2Work);
+ work->input.flags = C2FrameData::FLAG_END_OF_STREAM;
+ work->input.ordinal.timestamp = mLastTimestamp;
+ work->input.ordinal.frameIndex = mFrameIndex++;
+ work->input.buffers.clear();
+ work->worklets.clear();
+ work->worklets.emplace_back(new C2Worklet);
+ std::list<std::unique_ptr<C2Work>> items;
+ items.push_back(std::move(work));
+
+ c2_status_t err = comp->queue_nb(&items);
+ return (err == C2_OK) ? OK : UNKNOWN_ERROR;
+ }
+
+ void dispatchDataSpaceChanged(
+ int32_t dataSpace, int32_t aspects, int32_t pixelFormat) override {
+ // TODO
+ (void)dataSpace;
+ (void)aspects;
+ (void)pixelFormat;
+ }
+
+private:
+ wp<GraphicBufferSource> mSource;
+ std::weak_ptr<C2Component> mComp;
+
+ // Needed for ComponentWrapper implementation
+ int64_t mLastTimestamp;
+ std::shared_ptr<C2Allocator> mAllocator;
+ std::atomic_uint64_t mFrameIndex;
+};
+
+InputSurfaceConnection::InputSurfaceConnection(
+ const sp<GraphicBufferSource> &source,
+ const std::shared_ptr<C2Component> &comp)
+ : mSource(source),
+ mImpl(new Impl(source, comp)) {
+}
+
+InputSurfaceConnection::~InputSurfaceConnection() {
+ disconnect();
+}
+
+bool InputSurfaceConnection::init() {
+ if (mImpl == nullptr) {
+ return false;
+ }
+ return mImpl->init();
+}
+
+void InputSurfaceConnection::disconnect() {
+ ALOGV("disconnect");
+ if (mSource != nullptr) {
+ (void)mSource->stop();
+ (void)mSource->release();
+ }
+ mImpl.clear();
+ mSource.clear();
+ ALOGV("disconnected");
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
diff --git a/media/libstagefright/codec2/Android.bp b/media/libstagefright/codec2/Android.bp
index ee5c3eb..e1ac44e 100644
--- a/media/libstagefright/codec2/Android.bp
+++ b/media/libstagefright/codec2/Android.bp
@@ -1,5 +1,6 @@
cc_library_shared {
name: "libstagefright_codec2",
+ vendor_available: true,
tags: [
"optional",
@@ -21,6 +22,16 @@
"include",
],
+ header_libs: [
+ "libhardware_headers",
+ "libutils_headers",
+ ],
+
+ export_header_lib_headers: [
+ "libhardware_headers",
+ "libutils_headers",
+ ],
+
sanitize: {
misc_undefined: [
"unsigned-integer-overflow",
@@ -37,6 +48,7 @@
cc_library_shared {
name: "libstagefright_simple_c2component",
+ vendor_available: true,
tags: [
"optional",
diff --git a/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurface.h b/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurface.h
new file mode 100644
index 0000000..e46d03c
--- /dev/null
+++ b/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurface.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 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 ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_H
+#define ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_H
+
+#include <memory>
+
+#include <C2Component.h>
+#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
+#include <media/stagefright/codec2/1.0/InputSurfaceConnection.h>
+
+namespace android {
+
+class GraphicBufferSource;
+
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+
+typedef ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer
+ HGraphicBufferProducer;
+typedef ::android::IGraphicBufferProducer BGraphicBufferProducer;
+
+// TODO: ::android::TWGraphicBufferProducer<IInputSurface>
+typedef ::android::TWGraphicBufferProducer<HGraphicBufferProducer> InputSurfaceBase;
+
+class InputSurface : public InputSurfaceBase {
+public:
+ virtual ~InputSurface() = default;
+
+ // Methods from IInputSurface
+ sp<InputSurfaceConnection> connectToComponent(
+ const std::shared_ptr<::android::C2Component> &comp);
+ // TODO: intf()
+
+ static sp<InputSurface> Create();
+
+private:
+ InputSurface(
+ const sp<BGraphicBufferProducer> &base,
+ const sp<::android::GraphicBufferSource> &source);
+
+ sp<::android::GraphicBufferSource> mSource;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_H
diff --git a/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurfaceConnection.h b/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurfaceConnection.h
new file mode 100644
index 0000000..fc19acd
--- /dev/null
+++ b/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurfaceConnection.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 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 ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_CONNECTION_H
+#define ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_CONNECTION_H
+
+#include <memory>
+
+#include <C2Component.h>
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
+#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
+#include <media/stagefright/codec2/1.0/InputSurfaceConnection.h>
+
+namespace android {
+
+class C2Allocator;
+
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+// TODO: inherit from IInputSurfaceConnection
+class InputSurfaceConnection : public RefBase {
+public:
+ virtual ~InputSurfaceConnection();
+
+ // From IInputSurfaceConnection
+ void disconnect();
+
+private:
+ friend class InputSurface;
+
+ // For InputSurface
+ InputSurfaceConnection(
+ const sp<GraphicBufferSource> &source, const std::shared_ptr<C2Component> &comp);
+ bool init();
+
+ InputSurfaceConnection() = delete;
+
+ class Impl;
+
+ sp<GraphicBufferSource> mSource;
+ sp<Impl> mImpl;
+
+ DISALLOW_EVIL_CONSTRUCTORS(InputSurfaceConnection);
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_CONNECTION_H
diff --git a/media/libstagefright/codec2/vndk/Android.bp b/media/libstagefright/codec2/vndk/Android.bp
index cdd0488..d6cbe96 100644
--- a/media/libstagefright/codec2/vndk/Android.bp
+++ b/media/libstagefright/codec2/vndk/Android.bp
@@ -10,6 +10,10 @@
cc_library_shared {
name: "libstagefright_codec2_vndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: [
"C2AllocatorIon.cpp",
@@ -23,12 +27,9 @@
"include",
],
- header_libs:[
- "libstagefright_codec2_internal",
- ],
-
include_dirs: [
"frameworks/av/media/libstagefright/codec2/include",
+ "frameworks/av/media/libstagefright/codec2/vndk/internal",
"frameworks/native/include/media/hardware",
],
@@ -42,7 +43,6 @@
"libhidlbase",
"libion",
"liblog",
- "libmedia",
"libstagefright_foundation",
"libui",
"libutils",
diff --git a/media/libstagefright/codec2/vndk/C2Buffer.cpp b/media/libstagefright/codec2/vndk/C2Buffer.cpp
index 0de8cde..511ffe0 100644
--- a/media/libstagefright/codec2/vndk/C2Buffer.cpp
+++ b/media/libstagefright/codec2/vndk/C2Buffer.cpp
@@ -271,6 +271,7 @@
new ReadViewBuddy::Impl(*mImpl, (uint8_t *)base, offset(), len),
[base, len](ReadViewBuddy::Impl *i) {
(void)i->getAllocation()->unmap(base, len, nullptr);
+ delete i;
});
return AcquirableReadViewBuddy(error, C2Fence(), ReadViewBuddy(rvi, 0, len));
} else {
@@ -300,6 +301,7 @@
new WriteViewBuddy::Impl(*mImpl, (uint8_t *)base, 0, len),
[base, len](WriteViewBuddy::Impl *i) {
(void)i->getAllocation()->unmap(base, len, nullptr);
+ delete i;
});
return AcquirableWriteViewBuddy(error, C2Fence(), WriteViewBuddy(rvi));
} else {
@@ -791,4 +793,14 @@
return mImpl->removeInfo(index);
}
+// static
+std::shared_ptr<C2Buffer> C2Buffer::CreateLinearBuffer(const C2ConstLinearBlock &block) {
+ return std::shared_ptr<C2Buffer>(new C2Buffer({ block }));
+}
+
+// static
+std::shared_ptr<C2Buffer> C2Buffer::CreateGraphicBuffer(const C2ConstGraphicBlock &block) {
+ return std::shared_ptr<C2Buffer>(new C2Buffer({ block }));
+}
+
} // namespace android
diff --git a/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp b/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp
index 911f0f8..9ea3589 100644
--- a/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp
+++ b/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp
@@ -15,7 +15,7 @@
*/
#define LOG_NDEBUG 0
-#define LOG_TAG "C2SoftAvcEncEnc"
+#define LOG_TAG "C2SoftAvcEnc"
#include <utils/Log.h>
#include <utils/misc.h>
diff --git a/media/libstagefright/codecs/cmds/codec2.cpp b/media/libstagefright/codecs/cmds/codec2.cpp
index d95bb07..8022b84 100644
--- a/media/libstagefright/codecs/cmds/codec2.cpp
+++ b/media/libstagefright/codecs/cmds/codec2.cpp
@@ -295,7 +295,7 @@
size_t size = 0u;
void *data = nullptr;
int64_t timestamp = 0u;
- MediaBuffer *buffer = nullptr;
+ MediaBufferBase *buffer = nullptr;
sp<ABuffer> csd;
if (csd0 != nullptr) {
csd = csd0;
diff --git a/media/libstagefright/foundation/avc_utils.cpp b/media/libstagefright/foundation/avc_utils.cpp
index 8414af3..e8a6083 100644
--- a/media/libstagefright/foundation/avc_utils.cpp
+++ b/media/libstagefright/foundation/avc_utils.cpp
@@ -537,49 +537,6 @@
return layerId;
}
-sp<ABuffer> MakeAACCodecSpecificData(
- unsigned profile, unsigned sampling_freq_index,
- unsigned channel_configuration, int32_t *sampleRate,
- int32_t *channelCount) {
- CHECK_LE(sampling_freq_index, 11u);
- static const int32_t kSamplingFreq[] = {
- 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
- 16000, 12000, 11025, 8000
- };
- *sampleRate = kSamplingFreq[sampling_freq_index];
- *channelCount = channel_configuration;
-
- static const uint8_t kStaticESDS[] = {
- 0x03, 22,
- 0x00, 0x00, // ES_ID
- 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag
-
- 0x04, 17,
- 0x40, // Audio ISO/IEC 14496-3
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
-
- 0x05, 2,
- // AudioSpecificInfo follows
-
- // oooo offf fccc c000
- // o - audioObjectType
- // f - samplingFreqIndex
- // c - channelConfig
- };
- sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + 2);
- memcpy(csd->data(), kStaticESDS, sizeof(kStaticESDS));
-
- csd->data()[sizeof(kStaticESDS)] =
- ((profile + 1) << 3) | (sampling_freq_index >> 1);
-
- csd->data()[sizeof(kStaticESDS) + 1] =
- ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
-
- return csd;
-}
-
bool ExtractDimensionsFromVOLHeader(
const uint8_t *data, size_t size, int32_t *width, int32_t *height) {
ABitReader br(&data[4], size - 4);
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
index 2ca66fb..c287559 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
@@ -90,11 +90,6 @@
const char *AVCProfileToString(uint8_t profile);
-sp<ABuffer> MakeAACCodecSpecificData(
- unsigned profile, unsigned sampling_freq_index,
- unsigned channel_configuration, int32_t *sampleRate,
- int32_t *channelCount);
-
// Given an MPEG4 video VOL-header chunk (starting with 0x00 0x00 0x01 0x2?)
// parse it and fill in dimensions, returns true iff successful.
bool ExtractDimensionsFromVOLHeader(
diff --git a/media/libstagefright/include/C2OMXNode.h b/media/libstagefright/include/C2OMXNode.h
new file mode 100644
index 0000000..3c007c4
--- /dev/null
+++ b/media/libstagefright/include/C2OMXNode.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 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 C2_OMX_NODE_H_
+#define C2_OMX_NODE_H_
+
+#include <atomic>
+
+#include <android/IOMXBufferSource.h>
+#include <media/IOMX.h>
+#include <media/OMXBuffer.h>
+
+namespace android {
+
+/**
+ * IOmxNode implementation around codec 2.0 component, only to be used in
+ * IGraphicBufferSource::configure. Only subset of IOmxNode API is implemented
+ * and others are left as stub. As a result, one cannot expect this IOmxNode
+ * to work in any other usage than IGraphicBufferSource.
+ */
+struct C2OMXNode : public BnOMXNode {
+ // TODO: this should take android::hardware::media::c2::V1_0::IComponent
+ explicit C2OMXNode(const std::shared_ptr<C2Component> &comp);
+ ~C2OMXNode() override = default;
+
+ // IOMXNode
+ status_t freeNode() override;
+ status_t sendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) override;
+ status_t getParameter(
+ OMX_INDEXTYPE index, void *params, size_t size) override;
+ status_t setParameter(
+ OMX_INDEXTYPE index, const void *params, size_t size) override;
+ status_t getConfig(
+ OMX_INDEXTYPE index, void *params, size_t size) override;
+ status_t setConfig(
+ OMX_INDEXTYPE index, const void *params, size_t size) override;
+ status_t setPortMode(OMX_U32 port_index, IOMX::PortMode mode) override;
+ status_t prepareForAdaptivePlayback(
+ OMX_U32 portIndex, OMX_BOOL enable,
+ OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) override;
+ status_t configureVideoTunnelMode(
+ OMX_U32 portIndex, OMX_BOOL tunneled,
+ OMX_U32 audioHwSync, native_handle_t **sidebandHandle) override;
+ status_t getGraphicBufferUsage(
+ OMX_U32 port_index, OMX_U32* usage) override;
+ status_t setInputSurface(
+ const sp<IOMXBufferSource> &bufferSource) override;
+ status_t allocateSecureBuffer(
+ OMX_U32 port_index, size_t size, buffer_id *buffer,
+ void **buffer_data, sp<NativeHandle> *native_handle) override;
+ status_t useBuffer(
+ OMX_U32 port_index, const OMXBuffer &omxBuf, buffer_id *buffer) override;
+ status_t freeBuffer(
+ OMX_U32 port_index, buffer_id buffer) override;
+ status_t fillBuffer(
+ buffer_id buffer, const OMXBuffer &omxBuf, int fenceFd) override;
+ status_t emptyBuffer(
+ buffer_id buffer, const OMXBuffer &omxBuf,
+ OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) override;
+ status_t getExtensionIndex(
+ const char *parameter_name,
+ OMX_INDEXTYPE *index) override;
+ status_t dispatchMessage(const omx_message &msg) override;
+
+ sp<IOMXBufferSource> getSource();
+
+private:
+ std::weak_ptr<C2Component> mComp;
+ sp<IOMXBufferSource> mBufferSource;
+ std::shared_ptr<C2Allocator> mAllocator;
+ std::atomic_uint64_t mFrameIndex;
+};
+
+} // namespace android
+
+#endif // C2_OMX_NODE_H_
diff --git a/media/libstagefright/include/CCodecBufferChannel.h b/media/libstagefright/include/CCodecBufferChannel.h
index e64f984..eb3255f 100644
--- a/media/libstagefright/include/CCodecBufferChannel.h
+++ b/media/libstagefright/include/CCodecBufferChannel.h
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-#ifndef A_BUFFER_CHANNEL_H_
+#ifndef CCODEC_BUFFER_CHANNEL_H_
-#define A_BUFFER_CHANNEL_H_
+#define CCODEC_BUFFER_CHANNEL_H_
#include <map>
#include <memory>
@@ -26,13 +26,19 @@
#include <C2Buffer.h>
#include <C2Component.h>
-#include <media/stagefright/foundation/Mutexed.h>
#include <media/stagefright/bqhelper/GraphicBufferSource.h>
+#include <media/stagefright/codec2/1.0/InputSurface.h>
+#include <media/stagefright/foundation/Mutexed.h>
#include <media/stagefright/CodecBase.h>
#include <media/ICrypto.h>
+#include "InputSurfaceWrapper.h"
+
namespace android {
+using ::android::hardware::media::c2::V1_0::implementation::InputSurface;
+using ::android::hardware::media::c2::V1_0::implementation::InputSurfaceConnection;
+
/**
* BufferChannelBase implementation for CCodec.
*/
@@ -76,7 +82,7 @@
* Set GraphicBufferSource object from which the component extracts input
* buffers.
*/
- status_t setGraphicBufferSource(const sp<GraphicBufferSource> &source);
+ status_t setInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface);
/**
* Start queueing buffers to the component. This object should never queue
@@ -103,7 +109,6 @@
class Buffers;
class InputBuffers;
class OutputBuffers;
- class InputBufferClient;
private:
class QueueGuard;
@@ -156,8 +161,6 @@
bool mRunning;
};
- class C2ComponentWrapper;
-
void feedInputBufferIfAvailable();
QueueSync mSync;
@@ -166,7 +169,6 @@
int32_t mHeapSeqNum;
std::shared_ptr<C2Component> mComponent;
- std::shared_ptr<InputBufferClient> mInputClient;
std::function<void(status_t, enum ActionCode)> mOnError;
std::shared_ptr<C2BlockPool> mInputAllocator;
QueueSync mQueueSync;
@@ -180,6 +182,8 @@
sp<MemoryDealer> makeMemoryDealer(size_t heapSize);
Mutexed<sp<Surface>> mSurface;
+ std::shared_ptr<InputSurfaceWrapper> mInputSurface;
+
inline bool hasCryptoOrDescrambler() {
return mCrypto != NULL || mDescrambler != NULL;
}
@@ -187,4 +191,4 @@
} // namespace android
-#endif // A_BUFFER_CHANNEL_H_
+#endif // CCODEC_BUFFER_CHANNEL_H_
diff --git a/media/libstagefright/include/InputSurfaceWrapper.h b/media/libstagefright/include/InputSurfaceWrapper.h
new file mode 100644
index 0000000..a4d8f29
--- /dev/null
+++ b/media/libstagefright/include/InputSurfaceWrapper.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 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 INPUT_SURFACE_WRAPPER_H_
+
+#define INPUT_SURFACE_WRAPPER_H_
+
+namespace android {
+
+/**
+ * Wrapper interface around InputSurface.
+ */
+class InputSurfaceWrapper {
+public:
+ virtual ~InputSurfaceWrapper() = default;
+
+ /**
+ * Connect the surface with |comp| and start pushing buffers. A surface can
+ * connect to at most one component at a time.
+ *
+ * \return OK successfully connected to |comp|
+ * \return ALREADY_EXISTS already connected to another component.
+ */
+ virtual status_t connect(const std::shared_ptr<C2Component> &comp) = 0;
+
+ /**
+ * Disconnect the surface from the component if any.
+ */
+ virtual void disconnect() = 0;
+
+ // TODO: intf()
+};
+
+} // namespace android
+
+#endif // INPUT_SURFACE_WRAPPER_H_
diff --git a/media/libstagefright/include/media/stagefright/AudioPlayer.h b/media/libstagefright/include/media/stagefright/AudioPlayer.h
index e971762..7c2c36f 100644
--- a/media/libstagefright/include/media/stagefright/AudioPlayer.h
+++ b/media/libstagefright/include/media/stagefright/AudioPlayer.h
@@ -69,7 +69,7 @@
sp<MediaSource> mSource;
sp<AudioTrack> mAudioTrack;
- MediaBuffer *mInputBuffer;
+ MediaBufferBase *mInputBuffer;
int mSampleRate;
int64_t mLatencyUs;
@@ -91,7 +91,7 @@
bool mIsFirstBuffer;
status_t mFirstBufferResult;
- MediaBuffer *mFirstBuffer;
+ MediaBufferBase *mFirstBuffer;
sp<MediaPlayerBase::AudioSink> mAudioSink;
diff --git a/media/libstagefright/include/media/stagefright/AudioSource.h b/media/libstagefright/include/media/stagefright/AudioSource.h
index f66b92d..206d322 100644
--- a/media/libstagefright/include/media/stagefright/AudioSource.h
+++ b/media/libstagefright/include/media/stagefright/AudioSource.h
@@ -56,11 +56,11 @@
int16_t getMaxAmplitude();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
+ MediaBufferBase **buffer, const ReadOptions *options = NULL);
virtual status_t setStopTimeUs(int64_t stopTimeUs);
status_t dataCallback(const AudioRecord::Buffer& buffer);
- virtual void signalBufferReturned(MediaBuffer *buffer);
+ virtual void signalBufferReturned(MediaBufferBase *buffer);
status_t setInputDevice(audio_port_handle_t deviceId);
status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
diff --git a/media/libstagefright/include/media/stagefright/CCodec.h b/media/libstagefright/include/media/stagefright/CCodec.h
index 9307f3f..24ee0a3 100644
--- a/media/libstagefright/include/media/stagefright/CCodec.h
+++ b/media/libstagefright/include/media/stagefright/CCodec.h
@@ -24,7 +24,6 @@
#include <android/native_window.h>
#include <media/hardware/MetadataBufferType.h>
#include <media/stagefright/foundation/Mutexed.h>
-#include <media/stagefright/bqhelper/GraphicBufferSource.h>
#include <media/stagefright/CodecBase.h>
#include <media/stagefright/FrameRenderTracker.h>
#include <media/stagefright/MediaDefs.h>
@@ -36,6 +35,7 @@
namespace android {
class CCodecBufferChannel;
+class InputSurfaceWrapper;
class CCodec : public CodecBase {
public:
@@ -81,7 +81,7 @@
void createInputSurface();
void setInputSurface(const sp<PersistentSurface> &surface);
- status_t setupInputSurface(const sp<GraphicBufferSource> &source);
+ status_t setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface);
void setDeadline(const TimePoint &deadline);
diff --git a/media/libstagefright/include/media/stagefright/CallbackMediaSource.h b/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
index 944d951..33453fa 100644
--- a/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
@@ -33,7 +33,7 @@
virtual status_t stop();
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
+ MediaBufferBase **buffer, const ReadOptions *options = NULL);
virtual status_t pause();
private:
diff --git a/media/libstagefright/include/media/stagefright/CameraSource.h b/media/libstagefright/include/media/stagefright/CameraSource.h
index 945e1be..475976b 100644
--- a/media/libstagefright/include/media/stagefright/CameraSource.h
+++ b/media/libstagefright/include/media/stagefright/CameraSource.h
@@ -97,7 +97,7 @@
virtual status_t start(MetaData *params = NULL);
virtual status_t stop() { return reset(); }
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
+ MediaBufferBase **buffer, const ReadOptions *options = NULL);
virtual status_t setStopTimeUs(int64_t stopTimeUs);
/**
@@ -127,7 +127,7 @@
*/
MetadataBufferType metaDataStoredInVideoBuffers() const;
- virtual void signalBufferReturned(MediaBuffer* buffer);
+ virtual void signalBufferReturned(MediaBufferBase* buffer);
protected:
diff --git a/media/libstagefright/include/media/stagefright/CameraSourceTimeLapse.h b/media/libstagefright/include/media/stagefright/CameraSourceTimeLapse.h
index b066f9a..533e33b 100644
--- a/media/libstagefright/include/media/stagefright/CameraSourceTimeLapse.h
+++ b/media/libstagefright/include/media/stagefright/CameraSourceTimeLapse.h
@@ -107,7 +107,7 @@
// Stores a copy of the MediaBuffer read in the last read() call after
// mQuickStop was true.
- MediaBuffer* mLastReadBufferCopy;
+ MediaBufferBase* mLastReadBufferCopy;
// Status code for last read.
status_t mLastReadStatus;
@@ -128,10 +128,10 @@
// Wrapper over CameraSource::signalBufferReturned() to implement quick stop.
// It only handles the case when mLastReadBufferCopy is signalled. Otherwise
// it calls the base class' function.
- virtual void signalBufferReturned(MediaBuffer* buffer);
+ virtual void signalBufferReturned(MediaBufferBase* buffer);
// Wrapper over CameraSource::read() to implement quick stop.
- virtual status_t read(MediaBuffer **buffer, const ReadOptions *options = NULL);
+ virtual status_t read(MediaBufferBase **buffer, const ReadOptions *options = NULL);
// mSkipCurrentFrame is set to true in dataCallbackTimestamp() if the current
// frame needs to be skipped and this function just returns the value of mSkipCurrentFrame.
@@ -170,7 +170,7 @@
// Convenience function to fill mLastReadBufferCopy from the just read
// buffer.
- void fillLastReadBufferCopy(MediaBuffer& sourceBuffer);
+ void fillLastReadBufferCopy(MediaBufferBase& sourceBuffer);
// If the passed in size (width x height) is a supported video/preview size,
// the function sets the camera's video/preview size to it and returns true.
diff --git a/media/libstagefright/include/media/stagefright/JPEGSource.h b/media/libstagefright/include/media/stagefright/JPEGSource.h
index 9fcbfc2..8ab3d11 100644
--- a/media/libstagefright/include/media/stagefright/JPEGSource.h
+++ b/media/libstagefright/include/media/stagefright/JPEGSource.h
@@ -33,7 +33,7 @@
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
+ MediaBufferBase **buffer, const ReadOptions *options = NULL);
protected:
virtual ~JPEGSource();
diff --git a/media/libstagefright/include/media/stagefright/MediaAdapter.h b/media/libstagefright/include/media/stagefright/MediaAdapter.h
index 4b47160..589c827 100644
--- a/media/libstagefright/include/media/stagefright/MediaAdapter.h
+++ b/media/libstagefright/include/media/stagefright/MediaAdapter.h
@@ -40,13 +40,13 @@
virtual status_t stop();
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
+ MediaBufferBase **buffer, const ReadOptions *options = NULL);
/////////////////////////////////////////////////
// Inherited functions from MediaBufferObserver
/////////////////////////////////////////////////
- virtual void signalBufferReturned(MediaBuffer *buffer);
+ virtual void signalBufferReturned(MediaBufferBase *buffer);
/////////////////////////////////////////////////
// Non-inherited functions:
diff --git a/media/libstagefright/include/media/stagefright/MediaBufferBase.h b/media/libstagefright/include/media/stagefright/MediaBufferBase.h
new file mode 120000
index 0000000..80e49b0
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/MediaBufferBase.h
@@ -0,0 +1 @@
+../../../../libmediaextractor/include/media/stagefright/MediaBufferBase.h
\ No newline at end of file
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecSource.h b/media/libstagefright/include/media/stagefright/MediaCodecSource.h
index eec115e..a68cc19 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecSource.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecSource.h
@@ -57,13 +57,13 @@
virtual status_t pause(MetaData *params);
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer,
+ MediaBufferBase **buffer,
const ReadOptions *options = NULL);
virtual status_t setStopTimeUs(int64_t stopTimeUs);
// MediaBufferObserver
- virtual void signalBufferReturned(MediaBuffer *buffer);
+ virtual void signalBufferReturned(MediaBufferBase *buffer);
// for AHandlerReflector
void onMessageReceived(const sp<AMessage> &msg);
@@ -136,7 +136,7 @@
sp<AMessage> mEncoderActivityNotify;
sp<IGraphicBufferProducer> mGraphicBufferProducer;
sp<PersistentSurface> mPersistentSurface;
- List<MediaBuffer *> mInputBufferQueue;
+ List<MediaBufferBase *> mInputBufferQueue;
List<size_t> mAvailEncoderInputIndices;
List<int64_t> mDecodingTimeQueue; // decoding time (us) for video
int64_t mInputBufferTimeOffsetUs;
@@ -149,7 +149,7 @@
struct Output {
Output();
- List<MediaBuffer*> mBufferQueue;
+ List<MediaBufferBase*> mBufferQueue;
bool mEncoderReachedEOS;
status_t mErrorCode;
Condition mCond;
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
index 4d2f4f0..90c66eb 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
@@ -57,7 +57,7 @@
const sp<ExtractorPlugin> &plugin, List<sp<ExtractorPlugin>> &pluginList);
static MediaExtractor::CreatorFunc sniff(DataSourceBase *source,
- String8 *mimeType, float *confidence, sp<AMessage> *meta,
+ float *confidence, void **meta, MediaExtractor::FreeMetaFunc *freeMeta,
sp<ExtractorPlugin> &plugin);
static void UpdateExtractors(const char *newUpdateApkPath);
diff --git a/media/libstagefright/include/media/stagefright/NdkUtils.h b/media/libstagefright/include/media/stagefright/NdkUtils.h
new file mode 100644
index 0000000..a68884a
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/NdkUtils.h
@@ -0,0 +1,31 @@
+/*
+ * 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 NDK_UTILS_H_
+
+#define NDK_UTILS_H_
+
+#include <media/stagefright/MetaData.h>
+#include <media/NdkWrapper.h>
+
+namespace android {
+
+sp<MetaData> convertMediaFormatWrapperToMetaData(
+ const sp<AMediaFormatWrapper> &fmt);
+
+} // namespace android
+
+#endif // NDK_UTILS_H_
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 6a2e39b..5e5ef6e 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -107,8 +107,8 @@
struct Sample {
Sample();
- Sample(MediaBuffer *buffer, int64_t timeUs);
- MediaBuffer *mBuffer;
+ Sample(MediaBufferBase *buffer, int64_t timeUs);
+ MediaBufferBase *mBuffer;
int64_t mSampleTimeUs;
};
@@ -150,7 +150,7 @@
bool getTotalBitrate(int64_t *bitRate) const;
status_t updateDurationAndBitrate();
- status_t appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer);
+ status_t appendVorbisNumPageSamples(MediaBufferBase *mbuf, const sp<ABuffer> &buffer);
DISALLOW_EVIL_CONSTRUCTORS(NuMediaExtractor);
};
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
index 22a8210..509e669 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
@@ -40,8 +40,6 @@
virtual sp<MetaData> getMetaData();
virtual status_t getMetrics(Parcel *reply);
virtual uint32_t flags() const;
- virtual char* getDrmTrackInfo(size_t trackID, int * len);
- virtual void setUID(uid_t uid);
virtual status_t setMediaCas(const HInterfaceToken &casToken);
virtual const char * name();
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
index d1afa6a..a9bf820 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
@@ -35,7 +35,7 @@
virtual status_t stop();
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer,
+ MediaBufferBase **buffer,
const MediaSource::ReadOptions *options = NULL);
virtual status_t pause();
virtual status_t setStopTimeUs(int64_t stopTimeUs);
diff --git a/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
index 3006b45..23defb4 100644
--- a/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
+++ b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
@@ -65,7 +65,7 @@
virtual sp<MetaData> getFormat();
// reads from the source. This call always blocks.
- virtual status_t read(MediaBuffer **buffer, const ReadOptions *options);
+ virtual status_t read(MediaBufferBase **buffer, const ReadOptions *options);
// unsupported methods
virtual status_t pause() { return INVALID_OPERATION; }
@@ -104,7 +104,8 @@
// do the actual reading
status_t doRead(
- Mutexed<ProtectedState>::Locked &me, MediaBuffer **buffer, const ReadOptions *options);
+ Mutexed<ProtectedState>::Locked &me, MediaBufferBase **buffer,
+ const ReadOptions *options);
};
} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h b/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
index 2e495f9..d49e44c 100644
--- a/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
@@ -79,7 +79,7 @@
// For the MediaSource interface for use by StageFrightRecorder:
virtual status_t start(MetaData *params = NULL);
virtual status_t stop();
- virtual status_t read(MediaBuffer **buffer,
+ virtual status_t read(MediaBufferBase **buffer,
const ReadOptions *options = NULL);
virtual sp<MetaData> getFormat();
@@ -90,7 +90,7 @@
// The call for the StageFrightRecorder to tell us that
// it is done using the MediaBuffer data so that its state
// can be set to FREE for dequeuing
- virtual void signalBufferReturned(MediaBuffer* buffer);
+ virtual void signalBufferReturned(MediaBufferBase* buffer);
// end of MediaSource interface
// getTimestamp retrieves the timestamp associated with the image
@@ -236,7 +236,7 @@
Condition mMediaBuffersAvailableCondition;
// Allocate and return a new MediaBuffer and pass the ANW buffer as metadata into it.
- void passMetadataBuffer_l(MediaBuffer **buffer, ANativeWindowBuffer *bufferHandle) const;
+ void passMetadataBuffer_l(MediaBufferBase **buffer, ANativeWindowBuffer *bufferHandle) const;
// Avoid copying and equating and default constructor
DISALLOW_EVIL_CONSTRUCTORS(SurfaceMediaSource);
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 1dac171..d0b17e0 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -163,7 +163,7 @@
}
status_t AnotherPacketSource::read(
- MediaBuffer **out, const ReadOptions *) {
+ MediaBufferBase **out, const ReadOptions *) {
*out = NULL;
Mutex::Autolock autoLock(mLock);
@@ -202,7 +202,7 @@
seg.mMaxDequeTimeUs = timeUs;
}
- MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
+ MediaBufferBase *mediaBuffer = new MediaBuffer(buffer);
sp<MetaData> bufmeta = mediaBuffer->meta_data();
bufmeta->setInt64(kKeyTime, timeUs);
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index 3abd573..f4a6acb 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -39,7 +39,7 @@
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
+ MediaBufferBase **buffer, const ReadOptions *options = NULL);
void clear();
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 86c7211..3d9c791 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -658,7 +658,7 @@
requestedSeekTimeUs, requestedSeekTimeUs / 1E6);
}
- MediaBuffer *buffer = NULL;
+ MediaBufferBase *buffer = NULL;
options.setSeekTo(
requestedSeekTimeUs, MediaSource::ReadOptions::SEEK_NEXT_SYNC);
@@ -679,7 +679,7 @@
}
status_t err;
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
for (;;) {
err = codec->read(&buffer, &options);
options.clearSeekTo();
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 68f8bdd..201a5df 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -219,7 +219,7 @@
return csd;
}
-sp<ABuffer> MakeAACCodecSpecificData(const char *params) {
+static sp<ABuffer> MakeAACCodecSpecificData(const char *params) {
AString val;
CHECK(GetAttribute(params, "config", &val));
@@ -257,7 +257,7 @@
}
// From mpeg4-generic configuration data.
-sp<ABuffer> MakeAACCodecSpecificData2(const char *params) {
+static sp<ABuffer> MakeAACCodecSpecificData2(const char *params) {
AString val;
unsigned long objectType;
if (GetAttribute(params, "objectType", &val)) {
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 8604b69..4ce8a0c 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -173,7 +173,7 @@
return OK;
}
-static void StripStartcode(MediaBuffer *buffer) {
+static void StripStartcode(MediaBufferBase *buffer) {
if (buffer->range_length() < 4) {
return;
}
@@ -195,7 +195,7 @@
#if 0
if (mMode == H264) {
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
CHECK_EQ(mSource->read(&buffer), (status_t)OK);
StripStartcode(buffer);
@@ -265,7 +265,7 @@
}
void ARTPWriter::onRead(const sp<AMessage> &msg) {
- MediaBuffer *mediaBuf;
+ MediaBufferBase *mediaBuf;
status_t err = mSource->read(&mediaBuf);
if (err != OK) {
@@ -523,7 +523,7 @@
ALOGI("%s", sdp.c_str());
}
-void ARTPWriter::makeH264SPropParamSets(MediaBuffer *buffer) {
+void ARTPWriter::makeH264SPropParamSets(MediaBufferBase *buffer) {
static const char kStartCode[] = "\x00\x00\x00\x01";
const uint8_t *data =
@@ -567,7 +567,7 @@
send(buffer, true /* isRTCP */);
}
-void ARTPWriter::sendAVCData(MediaBuffer *mediaBuf) {
+void ARTPWriter::sendAVCData(MediaBufferBase *mediaBuf) {
// 12 bytes RTP header + 2 bytes for the FU-indicator and FU-header.
CHECK_GE(kMaxPacketSize, 12u + 2u);
@@ -663,7 +663,7 @@
mLastNTPTime = GetNowNTP();
}
-void ARTPWriter::sendH263Data(MediaBuffer *mediaBuf) {
+void ARTPWriter::sendH263Data(MediaBufferBase *mediaBuf) {
CHECK_GE(kMaxPacketSize, 12u + 2u);
int64_t timeUs;
@@ -741,7 +741,7 @@
return frameSize;
}
-void ARTPWriter::sendAMRData(MediaBuffer *mediaBuf) {
+void ARTPWriter::sendAMRData(MediaBufferBase *mediaBuf) {
const uint8_t *mediaData =
(const uint8_t *)mediaBuf->data() + mediaBuf->range_offset();
diff --git a/media/libstagefright/rtsp/ARTPWriter.h b/media/libstagefright/rtsp/ARTPWriter.h
index 92a64f2..2f13486 100644
--- a/media/libstagefright/rtsp/ARTPWriter.h
+++ b/media/libstagefright/rtsp/ARTPWriter.h
@@ -110,13 +110,13 @@
void addSR(const sp<ABuffer> &buffer);
void addSDES(const sp<ABuffer> &buffer);
- void makeH264SPropParamSets(MediaBuffer *buffer);
+ void makeH264SPropParamSets(MediaBufferBase *buffer);
void dumpSessionDesc();
void sendBye();
- void sendAVCData(MediaBuffer *mediaBuf);
- void sendH263Data(MediaBuffer *mediaBuf);
- void sendAMRData(MediaBuffer *mediaBuf);
+ void sendAVCData(MediaBufferBase *mediaBuf);
+ void sendH263Data(MediaBufferBase *mediaBuf);
+ void sendAMRData(MediaBufferBase *mediaBuf);
void send(const sp<ABuffer> &buffer, bool isRTCP);
diff --git a/media/libstagefright/tests/DummyRecorder.cpp b/media/libstagefright/tests/DummyRecorder.cpp
index 4f560cb..c79e6b1 100644
--- a/media/libstagefright/tests/DummyRecorder.cpp
+++ b/media/libstagefright/tests/DummyRecorder.cpp
@@ -75,7 +75,7 @@
}
status_t err = OK;
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
ALOGV("A fake writer accessing the frames");
while (mStarted && (err = mSource->read(&buffer)) == OK){
// if not getting a valid buffer from source, then exit
diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
index 051108f..1b1c3b8 100644
--- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp
+++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
@@ -601,7 +601,7 @@
// fakes reading from a media source
status_t readFromSource() {
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
status_t err = mSource->read(&buffer);
if (err != OK) {
return err;
diff --git a/media/libstagefright/webm/WebmFrame.cpp b/media/libstagefright/webm/WebmFrame.cpp
index e5134ed..4b0d47c 100644
--- a/media/libstagefright/webm/WebmFrame.cpp
+++ b/media/libstagefright/webm/WebmFrame.cpp
@@ -27,7 +27,7 @@
using namespace webm;
namespace {
-sp<ABuffer> toABuffer(MediaBuffer *mbuf) {
+sp<ABuffer> toABuffer(MediaBufferBase *mbuf) {
sp<ABuffer> abuf = new ABuffer(mbuf->range_length());
memcpy(abuf->data(), (uint8_t*) mbuf->data() + mbuf->range_offset(), mbuf->range_length());
return abuf;
@@ -46,7 +46,7 @@
mEos(true) {
}
-WebmFrame::WebmFrame(int type, bool key, uint64_t absTimecode, MediaBuffer *mbuf)
+WebmFrame::WebmFrame(int type, bool key, uint64_t absTimecode, MediaBufferBase *mbuf)
: mType(type),
mKey(key),
mAbsTimecode(absTimecode),
diff --git a/media/libstagefright/webm/WebmFrame.h b/media/libstagefright/webm/WebmFrame.h
index 4f0b055..a410a87 100644
--- a/media/libstagefright/webm/WebmFrame.h
+++ b/media/libstagefright/webm/WebmFrame.h
@@ -30,7 +30,7 @@
const bool mEos;
WebmFrame();
- WebmFrame(int type, bool key, uint64_t absTimecode, MediaBuffer *buf);
+ WebmFrame(int type, bool key, uint64_t absTimecode, MediaBufferBase *buf);
~WebmFrame() {}
sp<WebmElement> SimpleBlock(uint64_t baseTimecode) const;
diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp
index 420890b..0d4c699 100644
--- a/media/libstagefright/webm/WebmFrameThread.cpp
+++ b/media/libstagefright/webm/WebmFrameThread.cpp
@@ -337,7 +337,7 @@
mStartTimeUs = kUninitialized;
status_t err = OK;
- MediaBuffer *buffer;
+ MediaBufferBase *buffer;
while (!mDone && (err = mSource->read(&buffer, NULL)) == OK) {
if (buffer->range_length() == 0) {
buffer->release();
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index f190f80..9d00e5e 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -44,7 +44,15 @@
};
NdkDataSource::NdkDataSource(AMediaDataSource *dataSource)
- : mDataSource(dataSource) {
+ : mDataSource(AMediaDataSource_new()) {
+ AMediaDataSource_setReadAt(mDataSource, dataSource->readAt);
+ AMediaDataSource_setGetSize(mDataSource, dataSource->getSize);
+ AMediaDataSource_setClose(mDataSource, dataSource->close);
+ AMediaDataSource_setUserdata(mDataSource, dataSource->userdata);
+}
+
+NdkDataSource::~NdkDataSource() {
+ AMediaDataSource_delete(mDataSource);
}
status_t NdkDataSource::initCheck() const {
diff --git a/media/ndk/NdkMediaDataSourcePriv.h b/media/ndk/NdkMediaDataSourcePriv.h
index 65ddd2a..ea9c865 100644
--- a/media/ndk/NdkMediaDataSourcePriv.h
+++ b/media/ndk/NdkMediaDataSourcePriv.h
@@ -49,6 +49,9 @@
virtual String8 getMIMEType() const;
virtual void close();
+protected:
+ virtual ~NdkDataSource();
+
private:
Mutex mLock;
diff --git a/packages/MediaComponents/Android.mk b/packages/MediaComponents/Android.mk
index 7c7718e..22eea25 100644
--- a/packages/MediaComponents/Android.mk
+++ b/packages/MediaComponents/Android.mk
@@ -16,6 +16,12 @@
LOCAL_PATH := $(call my-dir)
+ifneq ($(TARGET_BUILD_PDK),true)
+# Build MediaComponents only if this is not a PDK build. MediaComponents won't
+# build in PDK builds because frameworks/base/core/java is not available but
+# IMediaSession2.aidl and IMediaSession2Callback.aidl are using classes from
+# frameworks/base/core/java.
+
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := MediaComponents
@@ -60,4 +66,6 @@
include $(BUILD_PACKAGE)
+endif # ifneq ($(TARGET_BUILD_PDK),true)
+
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/MediaComponents/src/com/android/media/IMediaSession2.aidl b/packages/MediaComponents/src/com/android/media/IMediaSession2.aidl
index 7702bda..9538c3d 100644
--- a/packages/MediaComponents/src/com/android/media/IMediaSession2.aidl
+++ b/packages/MediaComponents/src/com/android/media/IMediaSession2.aidl
@@ -63,4 +63,10 @@
// Get library service specific
//////////////////////////////////////////////////////////////////////////////////////////////
void getBrowserRoot(IMediaSession2Callback callback, in Bundle rootHints);
+ void getItem(IMediaSession2Callback callback, String mediaId);
+ void getChildren(IMediaSession2Callback callback, String parentId, int page, int pageSize,
+ in Bundle extras);
+ void search(IMediaSession2Callback callback, String query, in Bundle extras);
+ void getSearchResult(IMediaSession2Callback callback, String query, int page, int pageSize,
+ in Bundle extras);
}
diff --git a/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl b/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl
index a443bf8..b3aa59c 100644
--- a/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl
+++ b/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl
@@ -48,4 +48,9 @@
// Browser sepcific
//////////////////////////////////////////////////////////////////////////////////////////////
void onGetRootResult(in Bundle rootHints, String rootMediaId, in Bundle rootExtra);
+ void onItemLoaded(String mediaId, in Bundle result);
+ void onChildrenLoaded(String parentId, int page, int pageSize, in Bundle extras,
+ in List<Bundle> result);
+ void onSearchResultLoaded(String query, int page, int pageSize, in Bundle extras,
+ in List<Bundle> result);
}
diff --git a/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java b/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
index 7e928d7..76da42b 100644
--- a/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
@@ -19,11 +19,13 @@
import android.content.Context;
import android.media.MediaBrowser2;
import android.media.MediaBrowser2.BrowserCallback;
+import android.media.MediaItem2;
import android.media.MediaSession2.CommandButton;
import android.media.SessionToken2;
import android.media.update.MediaBrowser2Provider;
import android.os.Bundle;
import android.os.RemoteException;
+import android.text.TextUtils;
import android.util.Log;
import java.util.List;
@@ -61,28 +63,98 @@
}
@Override
- public void subscribe_impl(String parentId, Bundle options) {
+ public void subscribe_impl(String parentId, Bundle extras) {
// TODO(jaewan): Implement
}
@Override
- public void unsubscribe_impl(String parentId, Bundle options) {
+ public void unsubscribe_impl(String parentId, Bundle extras) {
// TODO(jaewan): Implement
}
@Override
public void getItem_impl(String mediaId) {
- // TODO(jaewan): Implement
+ if (mediaId == null) {
+ throw new IllegalArgumentException("mediaId shouldn't be null");
+ }
+
+ final IMediaSession2 binder = getSessionBinder();
+ if (binder != null) {
+ try {
+ binder.getItem(getControllerStub(), mediaId);
+ } catch (RemoteException e) {
+ // TODO(jaewan): Handle disconnect.
+ if (DEBUG) {
+ Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+ }
+ }
+ } else {
+ Log.w(TAG, "Session isn't active", new IllegalStateException());
+ }
}
@Override
- public void getChildren_impl(String parentId, int page, int pageSize, Bundle options) {
- // TODO(jaewan): Implement
+ public void getChildren_impl(String parentId, int page, int pageSize, Bundle extras) {
+ if (parentId == null) {
+ throw new IllegalArgumentException("parentId shouldn't be null");
+ }
+ if (page < 1 || pageSize < 1) {
+ throw new IllegalArgumentException("Neither page nor pageSize should be less than 1");
+ }
+
+ final IMediaSession2 binder = getSessionBinder();
+ if (binder != null) {
+ try {
+ binder.getChildren(getControllerStub(), parentId, page, pageSize, extras);
+ } catch (RemoteException e) {
+ // TODO(jaewan): Handle disconnect.
+ if (DEBUG) {
+ Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+ }
+ }
+ } else {
+ Log.w(TAG, "Session isn't active", new IllegalStateException());
+ }
}
@Override
- public void search_impl(String query, int page, int pageSize, Bundle extras) {
- // TODO(jaewan): Implement
+ public void search_impl(String query, Bundle extras) {
+ if (TextUtils.isEmpty(query)) {
+ throw new IllegalArgumentException("query shouldn't be empty");
+ }
+ final IMediaSession2 binder = getSessionBinder();
+ if (binder != null) {
+ try {
+ binder.search(getControllerStub(), query, extras);
+ } catch (RemoteException e) {
+ // TODO(jaewan): Handle disconnect.
+ if (DEBUG) {
+ Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+ }
+ }
+ } else {
+ Log.w(TAG, "Session isn't active", new IllegalStateException());
+ }
+ }
+
+ @Override
+ public void getSearchResult_impl(String query, int page, int pageSize, Bundle extras) {
+ if (TextUtils.isEmpty(query)) {
+ throw new IllegalArgumentException("query shouldn't be empty");
+ }
+ final IMediaSession2 binder = getSessionBinder();
+ if (binder != null) {
+ try {
+ binder.getSearchResult(getControllerStub(), query, page, pageSize, extras);
+ } catch (RemoteException e) {
+ // TODO(jaewan): Handle disconnect.
+ if (DEBUG) {
+ Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+ }
+ }
+ } else {
+ Log.w(TAG, "Session isn't active", new IllegalStateException());
+ }
}
public void onGetRootResult(
@@ -91,4 +163,24 @@
mCallback.onGetRootResult(rootHints, rootMediaId, rootExtra);
});
}
+
+ public void onItemLoaded(String mediaId, MediaItem2 item) {
+ getCallbackExecutor().execute(() -> {
+ mCallback.onItemLoaded(mediaId, item);
+ });
+ }
+
+ public void onChildrenLoaded(String parentId, int page, int pageSize, Bundle extras,
+ List<MediaItem2> result) {
+ getCallbackExecutor().execute(() -> {
+ mCallback.onChildrenLoaded(parentId, page, pageSize, extras, result);
+ });
+ }
+
+ public void onSearchResultLoaded(String query, int page, int pageSize, Bundle extras,
+ List<MediaItem2> result) {
+ getCallbackExecutor().execute(() -> {
+ mCallback.onSearchResultLoaded(query, page, pageSize, extras, result);
+ });
+ }
}
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
index 5ae37ee..5af4240 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
@@ -22,14 +22,14 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.media.AudioAttributes;
+import android.media.MediaController2;
+import android.media.MediaController2.ControllerCallback;
import android.media.MediaController2.PlaybackInfo;
import android.media.MediaItem2;
import android.media.MediaSession2;
import android.media.MediaSession2.Command;
import android.media.MediaSession2.CommandButton;
import android.media.MediaSession2.CommandGroup;
-import android.media.MediaController2;
-import android.media.MediaController2.ControllerCallback;
import android.media.MediaSession2.PlaylistParams;
import android.media.MediaSessionService2;
import android.media.PlaybackState2;
diff --git a/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java b/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java
index f51e246..4c4ef24 100644
--- a/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java
@@ -52,7 +52,7 @@
throw new IllegalArgumentException("dsd shouldn't be null");
}
if (metadata != null && !TextUtils.equals(mediaId, metadata.getMediaId())) {
- throw new IllegalArgumentException("metadata's id should be match with the mediaid");
+ throw new IllegalArgumentException("metadata's id should be matched with the mediaid");
}
mContext = context;
@@ -71,9 +71,9 @@
throw new IllegalArgumentException("mediaId shouldn't be null");
}
if (metadata != null && !TextUtils.equals(mediaId, metadata.getMediaId())) {
- throw new IllegalArgumentException("metadata's id should be match with the mediaid");
+ throw new IllegalArgumentException("metadata's id should be matched with the mediaid");
}
- mContext =context;
+ mContext = context;
mId = mediaId;
mMetadata = metadata;
mFlags = flags;
@@ -136,24 +136,21 @@
}
@Override
- public void setMetadata_impl(@NonNull MediaMetadata2 metadata) {
- if (metadata == null) {
- throw new IllegalArgumentException("metadata shouldn't be null");
- }
- if (TextUtils.isEmpty(metadata.getMediaId())) {
- throw new IllegalArgumentException("metadata must have a non-empty media id");
+ public void setMetadata_impl(@Nullable MediaMetadata2 metadata) {
+ if (metadata != null && !TextUtils.equals(mId, metadata.getMediaId())) {
+ throw new IllegalArgumentException("metadata's id should be matched with the mediaId");
}
mMetadata = metadata;
}
@Override
- public MediaMetadata2 getMetadata_impl() {
+ public @Nullable MediaMetadata2 getMetadata_impl() {
return mMetadata;
}
@Override
- public @Nullable String getMediaId_impl() {
- return mMetadata.getMediaId();
+ public @NonNull String getMediaId_impl() {
+ return mId;
}
@Override
diff --git a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
index b9dffcf..52db74e 100644
--- a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
@@ -66,15 +66,17 @@
public static class MediaLibrarySessionImpl extends MediaSession2Impl
implements MediaLibrarySessionProvider {
- private final MediaLibrarySessionCallback mCallback;
-
public MediaLibrarySessionImpl(Context context,
MediaPlayerInterface player, String id, VolumeProvider2 volumeProvider,
int ratingType, PendingIntent sessionActivity, Executor callbackExecutor,
MediaLibrarySessionCallback callback) {
super(context, player, id, volumeProvider, ratingType, sessionActivity,
callbackExecutor, callback);
- mCallback = callback;
+ // Don't put any extra initialization here. Here's the reason.
+ // System service will recognize this session inside of the super constructor and would
+ // connect to this session assuming that initialization is finished. However, if any
+ // initialization logic is here, calls from the server would fail.
+ // see: MediaSession2Stub#connect()
}
@Override
@@ -89,8 +91,7 @@
@Override
MediaLibrarySessionCallback getCallback() {
- // Equivalent to the (MediaLibrarySessionCallback) super.getCallback().
- return mCallback;
+ return (MediaLibrarySessionCallback) super.getCallback();
}
@Override
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2CallbackStub.java b/packages/MediaComponents/src/com/android/media/MediaSession2CallbackStub.java
index 07edf7e..852029a 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2CallbackStub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2CallbackStub.java
@@ -224,4 +224,72 @@
}
browser.onGetRootResult(rootHints, rootMediaId, rootExtra);
}
+
+
+ @Override
+ public void onItemLoaded(String mediaId, Bundle itemBundle) throws RuntimeException {
+ final MediaBrowser2Impl browser;
+ try {
+ browser = getBrowser();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+ return;
+ }
+ if (browser == null) {
+ // TODO(jaewan): Revisit here. Could be a bug
+ return;
+ }
+ browser.onItemLoaded(mediaId,
+ MediaItem2Impl.fromBundle(browser.getContext(), itemBundle));
+ }
+
+ @Override
+ public void onChildrenLoaded(String parentId, int page, int pageSize, Bundle extras,
+ List<Bundle> itemBundleList) throws RuntimeException {
+ final MediaBrowser2Impl browser;
+ try {
+ browser = getBrowser();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+ return;
+ }
+ if (browser == null) {
+ // TODO(jaewan): Revisit here. Could be a bug
+ return;
+ }
+
+ List<MediaItem2> result = null;
+ if (itemBundleList != null) {
+ result = new ArrayList<>();
+ for (Bundle bundle : itemBundleList) {
+ result.add(MediaItem2.fromBundle(browser.getContext(), bundle));
+ }
+ }
+ browser.onChildrenLoaded(parentId, page, pageSize, extras, result);
+ }
+
+ @Override
+ public void onSearchResultLoaded(String query, int page, int pageSize, Bundle extras,
+ List<Bundle> itemBundleList) throws RuntimeException {
+ final MediaBrowser2Impl browser;
+ try {
+ browser = getBrowser();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+ return;
+ }
+ if (browser == null) {
+ // TODO(jaewan): Revisit here. Could be a bug
+ return;
+ }
+
+ List<MediaItem2> result = null;
+ if (itemBundleList != null) {
+ result = new ArrayList<>();
+ for (Bundle bundle : itemBundleList) {
+ result.add(MediaItem2.fromBundle(browser.getContext(), bundle));
+ }
+ }
+ browser.onSearchResultLoaded(query, page, pageSize, extras, result);
+ }
}
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
index 74ac5b3..4a9a729 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
@@ -88,6 +88,22 @@
private final int mRatingType;
private final PendingIntent mSessionActivity;
+ // mPlayer is set to null when the session is closed, and we shouldn't throw an exception
+ // nor leave log always for using mPlayer when it's null. Here's the reason.
+ // When a MediaSession2 is closed, there could be a pended operation in the session callback
+ // executor that may want to access the player. Here's the sample code snippet for that.
+ //
+ // public void onFoo() {
+ // if (mPlayer == null) return; // first check
+ // mSessionCallbackExecutor.executor(() -> {
+ // // Error. Session may be closed and mPlayer can be null here.
+ // mPlayer.foo();
+ // });
+ // }
+ //
+ // By adding protective code, we can also protect APIs from being called after the close()
+ //
+ // TODO(jaewan): Should we put volatile here?
@GuardedBy("mLock")
private MediaPlayerInterface mPlayer;
@GuardedBy("mLock")
@@ -96,10 +112,6 @@
private PlaybackInfo mPlaybackInfo;
@GuardedBy("mLock")
private MyPlaybackListener mListener;
- @GuardedBy("mLock")
- private PlaylistParams mPlaylistParams;
- @GuardedBy("mLock")
- private List<MediaItem2> mPlaylist;
/**
* Can be only called by the {@link Builder#build()}.
@@ -146,9 +158,7 @@
mContext.getPackageName(), null, id, mSessionStub).getInstance();
}
- setPlayerLocked(player);
- mVolumeProvider = volumeProvider;
- mPlaybackInfo = createPlaybackInfo(volumeProvider, player.getAudioAttributes());
+ setPlayer(player, volumeProvider);
// Ask server for the sanity check, and starts
// Sanity check for making session ID unique 'per package' cannot be done in here.
@@ -198,14 +208,7 @@
if (player == null) {
throw new IllegalArgumentException("player shouldn't be null");
}
- PlaybackInfo info =
- createPlaybackInfo(null /* VolumeProvider */, player.getAudioAttributes());
- synchronized (mLock) {
- setPlayerLocked(player);
- mVolumeProvider = null;
- mPlaybackInfo = info;
- }
- mSessionStub.notifyPlaybackInfoChanged(info);
+ setPlayer(player, null);
}
@Override
@@ -218,25 +221,25 @@
if (volumeProvider == null) {
throw new IllegalArgumentException("volumeProvider shouldn't be null");
}
+ setPlayer(player, volumeProvider);
+ }
+
+ private void setPlayer(MediaPlayerInterface player, VolumeProvider2 volumeProvider) {
PlaybackInfo info = createPlaybackInfo(volumeProvider, player.getAudioAttributes());
synchronized (mLock) {
- setPlayerLocked(player);
+ if (mPlayer != null && mListener != null) {
+ // This might not work for a poorly implemented player.
+ mPlayer.removePlaybackListener(mListener);
+ }
+ mPlayer = player;
+ mListener = new MyPlaybackListener(this, player);
+ player.addPlaybackListener(mCallbackExecutor, mListener);
mVolumeProvider = volumeProvider;
mPlaybackInfo = info;
}
mSessionStub.notifyPlaybackInfoChanged(info);
}
- private void setPlayerLocked(MediaPlayerInterface player) {
- if (mPlayer != null && mListener != null) {
- // This might not work for a poorly implemented player.
- mPlayer.removePlaybackListener(mListener);
- }
- mPlayer = player;
- mListener = new MyPlaybackListener(this, player);
- player.addPlaybackListener(mCallbackExecutor, mListener);
- }
-
private PlaybackInfo createPlaybackInfo(VolumeProvider2 volumeProvider, AudioAttributes attrs) {
PlaybackInfo info;
if (volumeProvider == null) {
@@ -320,36 +323,56 @@
@Override
public void play_impl() {
ensureCallingThread();
- ensurePlayer();
- mPlayer.play();
+ final MediaPlayerInterface player = mPlayer;
+ if (player != null) {
+ player.play();
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
}
@Override
public void pause_impl() {
ensureCallingThread();
- ensurePlayer();
- mPlayer.pause();
+ final MediaPlayerInterface player = mPlayer;
+ if (player != null) {
+ player.pause();
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
}
@Override
public void stop_impl() {
ensureCallingThread();
- ensurePlayer();
- mPlayer.stop();
+ final MediaPlayerInterface player = mPlayer;
+ if (player != null) {
+ player.stop();
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
}
@Override
public void skipToPrevious_impl() {
ensureCallingThread();
- ensurePlayer();
- mPlayer.skipToPrevious();
+ final MediaPlayerInterface player = mPlayer;
+ if (player != null) {
+ player.skipToPrevious();
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
}
@Override
public void skipToNext_impl() {
ensureCallingThread();
- ensurePlayer();
- mPlayer.skipToNext();
+ final MediaPlayerInterface player = mPlayer;
+ if (player != null) {
+ player.skipToNext();
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
}
@Override
@@ -367,21 +390,27 @@
@Override
public void setPlaylistParams_impl(PlaylistParams params) {
if (params == null) {
- throw new IllegalArgumentException("PlaylistParams should not be null!");
+ throw new IllegalArgumentException("params shouldn't be null");
}
ensureCallingThread();
- ensurePlayer();
- synchronized (mLock) {
- mPlaylistParams = params;
+ final MediaPlayerInterface player = mPlayer;
+ if (player != null) {
+ player.setPlaylistParams(params);
+ mSessionStub.notifyPlaylistParamsChanged(params);
}
- mPlayer.setPlaylistParams(params);
- mSessionStub.notifyPlaylistParamsChanged(params);
}
@Override
public PlaylistParams getPlaylistParams_impl() {
- // TODO: Do we need to synchronize here for preparing Controller2.setPlaybackParams?
- return mPlaylistParams;
+ final MediaPlayerInterface player = mPlayer;
+ if (player != null) {
+ // TODO(jaewan): Is it safe to be called on any thread?
+ // Otherwise MediaSession2 should cache parameter of setPlaylistParams.
+ return player.getPlaylistParams();
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
+ return null;
}
//////////////////////////////////////////////////////////////////////////////////////
@@ -412,57 +441,84 @@
@Override
public void setPlaylist_impl(List<MediaItem2> playlist) {
if (playlist == null) {
- throw new IllegalArgumentException("Playlist should not be null!");
+ throw new IllegalArgumentException("playlist shouldn't be null");
}
ensureCallingThread();
- ensurePlayer();
- synchronized (mLock) {
- mPlaylist = playlist;
+ final MediaPlayerInterface player = mPlayer;
+ if (player != null) {
+ player.setPlaylist(playlist);
+ mSessionStub.notifyPlaylistChanged(playlist);
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
}
- mPlayer.setPlaylist(playlist);
- mSessionStub.notifyPlaylistChanged(playlist);
}
@Override
public List<MediaItem2> getPlaylist_impl() {
- synchronized (mLock) {
- return mPlaylist;
+ final MediaPlayerInterface player = mPlayer;
+ if (player != null) {
+ // TODO(jaewan): Is it safe to be called on any thread?
+ // Otherwise MediaSession2 should cache parameter of setPlaylist.
+ return player.getPlaylist();
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
}
+ return null;
}
@Override
public void prepare_impl() {
ensureCallingThread();
- ensurePlayer();
- mPlayer.prepare();
+ final MediaPlayerInterface player = mPlayer;
+ if (player != null) {
+ player.prepare();
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
}
@Override
public void fastForward_impl() {
ensureCallingThread();
- ensurePlayer();
- mPlayer.fastForward();
+ final MediaPlayerInterface player = mPlayer;
+ if (player != null) {
+ player.fastForward();
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
}
@Override
public void rewind_impl() {
ensureCallingThread();
- ensurePlayer();
- mPlayer.rewind();
+ final MediaPlayerInterface player = mPlayer;
+ if (player != null) {
+ player.rewind();
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
}
@Override
public void seekTo_impl(long pos) {
ensureCallingThread();
- ensurePlayer();
- mPlayer.seekTo(pos);
+ final MediaPlayerInterface player = mPlayer;
+ if (player != null) {
+ player.seekTo(pos);
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
}
@Override
public void setCurrentPlaylistItem_impl(int index) {
ensureCallingThread();
- ensurePlayer();
- mPlayer.setCurrentPlaylistItem(index);
+ final MediaPlayerInterface player = mPlayer;
+ if (player != null) {
+ player.setCurrentPlaylistItem(index);
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
}
@Override
@@ -497,10 +553,15 @@
@Override
public PlaybackState2 getPlaybackState_impl() {
ensureCallingThread();
- ensurePlayer();
- // TODO(jaewan): Is it safe to be called on any thread?
- // Otherwise we should cache the result from listener.
- return mPlayer.getPlaybackState();
+ final MediaPlayerInterface player = mPlayer;
+ if (player != null) {
+ // TODO(jaewan): Is it safe to be called on any thread?
+ // Otherwise MediaSession2 should cache the result from listener.
+ return player.getPlaybackState();
+ } else if (DEBUG) {
+ Log.d(TAG, "API calls after the close()", new IllegalStateException());
+ }
+ return null;
}
///////////////////////////////////////////////////
@@ -527,14 +588,6 @@
}*/
}
- private void ensurePlayer() {
- // TODO(jaewan): Should we pend command instead? Follow the decision from MP2.
- // Alternatively we can add a API like setAcceptsPendingCommands(boolean).
- if (mPlayer == null) {
- throw new IllegalStateException("Player isn't set");
- }
- }
-
private void notifyPlaybackStateChangedNotLocked(PlaybackState2 state) {
List<PlaybackListenerHolder> listeners = new ArrayList<>();
synchronized (mLock) {
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
index 43ad49d..759d580 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
@@ -36,6 +36,7 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.support.annotation.GuardedBy;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -539,9 +540,182 @@
});
}
+ @Override
+ public void getItem(IMediaSession2Callback caller, String mediaId) throws RuntimeException {
+ final MediaLibrarySessionImpl sessionImpl = getLibrarySession();
+ final ControllerInfo controller = getController(caller);
+ if (controller == null) {
+ if (DEBUG) {
+ Log.d(TAG, "getItem() from a controller that hasn't connected. Ignore");
+ }
+ return;
+ }
+ if (mediaId == null) {
+ if (DEBUG) {
+ Log.d(TAG, "mediaId shouldn't be null");
+ }
+ return;
+ }
+ sessionImpl.getCallbackExecutor().execute(() -> {
+ final MediaLibrarySessionImpl session = getLibrarySession();
+ if (session == null) {
+ return;
+ }
+ final ControllerInfoImpl controllerImpl = ControllerInfoImpl.from(controller);
+ MediaItem2 result = session.getCallback().onLoadItem(controller, mediaId);
+ try {
+ controllerImpl.getControllerBinder().onItemLoaded(
+ mediaId, result == null ? null : result.toBundle());
+ } catch (RemoteException e) {
+ // Controller may be died prematurely.
+ // TODO(jaewan): Handle this.
+ }
+ });
+ }
+
+ @Override
+ public void getChildren(IMediaSession2Callback caller, String parentId, int page,
+ int pageSize, Bundle extras) throws RuntimeException {
+ final MediaLibrarySessionImpl sessionImpl = getLibrarySession();
+ final ControllerInfo controller = getController(caller);
+ if (controller == null) {
+ if (DEBUG) {
+ Log.d(TAG, "getChildren() from a controller that hasn't connected. Ignore");
+ }
+ return;
+ }
+ if (parentId == null) {
+ if (DEBUG) {
+ Log.d(TAG, "parentId shouldn't be null");
+ }
+ return;
+ }
+ if (page < 1 || pageSize < 1) {
+ if (DEBUG) {
+ Log.d(TAG, "Neither page nor pageSize should be less than 1");
+ }
+ return;
+ }
+
+ sessionImpl.getCallbackExecutor().execute(() -> {
+ final MediaLibrarySessionImpl session = getLibrarySession();
+ if (session == null) {
+ return;
+ }
+ final ControllerInfoImpl controllerImpl = ControllerInfoImpl.from(controller);
+ List<MediaItem2> result = session.getCallback().onLoadChildren(
+ controller, parentId, page, pageSize, extras);
+ if (result != null && result.size() > pageSize) {
+ throw new IllegalArgumentException("onLoadChildren() shouldn't return media items "
+ + "more than pageSize. result.size()=" + result.size() + " pageSize="
+ + pageSize);
+ }
+
+ List<Bundle> bundleList = null;
+ if (result != null) {
+ bundleList = new ArrayList<>();
+ for (MediaItem2 item : result) {
+ bundleList.add(item == null ? null : item.toBundle());
+ }
+ }
+
+ try {
+ controllerImpl.getControllerBinder().onChildrenLoaded(
+ parentId, page, pageSize, extras, bundleList);
+ } catch (RemoteException e) {
+ // Controller may be died prematurely.
+ // TODO(jaewan): Handle this.
+ }
+ });
+ }
+
+ @Override
+ public void search(IMediaSession2Callback caller, String query, Bundle extras) {
+ final MediaLibrarySessionImpl sessionImpl = getLibrarySession();
+ final ControllerInfo controller = getController(caller);
+ if (controller == null) {
+ if (DEBUG) {
+ Log.d(TAG, "search() from a controller that hasn't connected. Ignore");
+ }
+ return;
+ }
+ if (TextUtils.isEmpty(query)) {
+ if (DEBUG) {
+ Log.d(TAG, "query shouldn't be empty");
+ }
+ return;
+ }
+
+ sessionImpl.getCallbackExecutor().execute(() -> {
+ final MediaLibrarySessionImpl session = getLibrarySession();
+ if (session == null) {
+ return;
+ }
+ final ControllerInfoImpl controllerImpl = ControllerInfoImpl.from(controller);
+ session.getCallback().onSearch(controller, query, extras);
+ });
+ }
+
+ @Override
+ public void getSearchResult(IMediaSession2Callback caller, String query, int page,
+ int pageSize, Bundle extras) {
+ final MediaLibrarySessionImpl sessionImpl = getLibrarySession();
+ final ControllerInfo controller = getController(caller);
+ if (controller == null) {
+ if (DEBUG) {
+ Log.d(TAG, "getSearchResult() from a controller that hasn't connected. Ignore");
+ }
+ return;
+ }
+ if (TextUtils.isEmpty(query)) {
+ if (DEBUG) {
+ Log.d(TAG, "query shouldn't be empty");
+ }
+ return;
+ }
+ if (page < 1 || pageSize < 1) {
+ if (DEBUG) {
+ Log.d(TAG, "Neither page nor pageSize should be less than 1");
+ }
+ return;
+ }
+
+ sessionImpl.getCallbackExecutor().execute(() -> {
+ final MediaLibrarySessionImpl session = getLibrarySession();
+ if (session == null) {
+ return;
+ }
+ final ControllerInfoImpl controllerImpl = ControllerInfoImpl.from(controller);
+ List<MediaItem2> result = session.getCallback().onLoadSearchResult(
+ controller, query, page, pageSize, extras);
+ if (result != null && result.size() > pageSize) {
+ throw new IllegalArgumentException("onLoadSearchResult() shouldn't return media "
+ + "items more than pageSize. result.size()=" + result.size() + " pageSize="
+ + pageSize);
+ }
+
+ List<Bundle> bundleList = null;
+ if (result != null) {
+ bundleList = new ArrayList<>();
+ for (MediaItem2 item : result) {
+ bundleList.add(item == null ? null : item.toBundle());
+ }
+ }
+
+ try {
+ controllerImpl.getControllerBinder().onSearchResultLoaded(
+ query, page, pageSize, extras, bundleList);
+ } catch (RemoteException e) {
+ // Controller may be died prematurely.
+ // TODO(jaewan): Handle this.
+ }
+ });
+ }
+
//////////////////////////////////////////////////////////////////////////////////////////////
// APIs for MediaSession2Impl
//////////////////////////////////////////////////////////////////////////////////////////////
+
// TODO(jaewan): Need a way to get controller with permissions
public List<ControllerInfo> getControllers() {
ArrayList<ControllerInfo> controllers = new ArrayList<>();
diff --git a/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java b/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
index b2b7959..f36aa43 100644
--- a/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
@@ -34,6 +34,8 @@
import android.os.IBinder;
import android.text.TextUtils;
+import java.util.List;
+
public class SessionToken2Impl implements SessionToken2Provider {
private static final String KEY_UID = "android.media.token.uid";
private static final String KEY_TYPE = "android.media.token.type";
@@ -73,25 +75,24 @@
}
}
mUid = uid;
- // calculate id and type
- Intent serviceIntent = new Intent(MediaLibraryService2.SERVICE_INTERFACE);
- serviceIntent.setClassName(packageName, serviceName);
- String id = getSessionId(manager.resolveService(serviceIntent,
- PackageManager.GET_META_DATA));
- int type = TYPE_LIBRARY_SERVICE;
- if (id == null) {
+
+ // Infer id and type from package name and service name
+ // TODO(jaewan): Handle multi-user.
+ String id = getSessionIdFromService(manager, MediaLibraryService2.SERVICE_INTERFACE,
+ packageName, serviceName);
+ if (id != null) {
+ mId = id;
+ mType = TYPE_LIBRARY_SERVICE;
+ } else {
// retry with session service
- serviceIntent.setClassName(packageName, serviceName);
- id = getSessionId(manager.resolveService(serviceIntent,
- PackageManager.GET_META_DATA));
- type = TYPE_SESSION_SERVICE;
+ mId = getSessionIdFromService(manager, MediaSessionService2.SERVICE_INTERFACE,
+ packageName, serviceName);
+ mType = TYPE_SESSION_SERVICE;
}
- if (id == null) {
+ if (mId == null) {
throw new IllegalArgumentException("service " + serviceName + " doesn't implement"
- + " session service nor library service");
+ + " session service nor library service. Use service's full name.");
}
- mId = id;
- mType = type;
mPackageName = packageName;
mServiceName = serviceName;
mSessionBinder = null;
@@ -109,6 +110,29 @@
mInstance = new SessionToken2(this);
}
+ private static String getSessionIdFromService(PackageManager manager, String serviceInterface,
+ String packageName, String serviceName) {
+ Intent serviceIntent = new Intent(serviceInterface);
+ serviceIntent.setPackage(packageName);
+ // Use queryIntentServices to find services with MediaLibraryService2.SERVICE_INTERFACE.
+ // We cannot use resolveService with intent specified class name, because resolveService
+ // ignores actions if Intent.setClassName() is specified.
+ List<ResolveInfo> list = manager.queryIntentServices(
+ serviceIntent, PackageManager.GET_META_DATA);
+ if (list != null) {
+ for (int i = 0; i < list.size(); i++) {
+ ResolveInfo resolveInfo = list.get(i);
+ if (resolveInfo == null || resolveInfo.serviceInfo == null) {
+ continue;
+ }
+ if (TextUtils.equals(resolveInfo.serviceInfo.name, serviceName)) {
+ return getSessionId(resolveInfo);
+ }
+ }
+ }
+ return null;
+ }
+
public static String getSessionId(ResolveInfo resolveInfo) {
if (resolveInfo == null || resolveInfo.serviceInfo == null) {
return null;
diff --git a/packages/MediaComponents/test/AndroidManifest.xml b/packages/MediaComponents/test/AndroidManifest.xml
index 48e4292..5ebe31a 100644
--- a/packages/MediaComponents/test/AndroidManifest.xml
+++ b/packages/MediaComponents/test/AndroidManifest.xml
@@ -34,7 +34,7 @@
<intent-filter>
<action android:name="android.media.MediaLibraryService2" />
</intent-filter>
- <meta-data android:name="android.media.session" android:value="TestBrowser" />
+ <meta-data android:name="android.media.session" android:value="TestLibrary" />
</service>
</application>
diff --git a/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java b/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
index eff4c3b..b60fde3 100644
--- a/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
@@ -18,7 +18,9 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -65,6 +67,9 @@
interface TestBrowserCallbackInterface extends TestControllerCallbackInterface {
// Browser specific callbacks
default void onGetRootResult(Bundle rootHints, String rootMediaId, Bundle rootExtra) {}
+ default void onItemLoaded(String mediaId, MediaItem2 result) {}
+ default void onChildrenLoaded(String parentId, int page, int pageSize, Bundle options,
+ List<MediaItem2> result) {}
}
@Test
@@ -90,6 +95,129 @@
assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
}
+ @Test
+ public void testGetItem() throws InterruptedException {
+ final String mediaId = MockMediaLibraryService2.MEDIA_ID_GET_ITEM;
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ final TestControllerCallbackInterface callback = new TestBrowserCallbackInterface() {
+ @Override
+ public void onItemLoaded(String mediaIdOut, MediaItem2 result) {
+ assertEquals(mediaId, mediaIdOut);
+ assertNotNull(result);
+ assertEquals(mediaId, result.getMediaId());
+ latch.countDown();
+ }
+ };
+
+ final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+ MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+ browser.getItem(mediaId);
+ assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testGetItemNullResult() throws InterruptedException {
+ final String mediaId = "random_media_id";
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ final TestControllerCallbackInterface callback = new TestBrowserCallbackInterface() {
+ @Override
+ public void onItemLoaded(String mediaIdOut, MediaItem2 result) {
+ assertEquals(mediaId, mediaIdOut);
+ assertNull(result);
+ latch.countDown();
+ }
+ };
+
+ final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+ MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+ browser.getItem(mediaId);
+ assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testGetChildren() throws InterruptedException {
+ final String parentId = MockMediaLibraryService2.PARENT_ID;
+ final int page = 4;
+ final int pageSize = 10;
+ final Bundle options = new Bundle();
+ options.putString(TAG, TAG);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ final TestControllerCallbackInterface callback = new TestBrowserCallbackInterface() {
+ @Override
+ public void onChildrenLoaded(String parentIdOut, int pageOut, int pageSizeOut,
+ Bundle optionsOut, List<MediaItem2> result) {
+ assertEquals(parentId, parentIdOut);
+ assertEquals(page, pageOut);
+ assertEquals(pageSize, pageSizeOut);
+ assertTrue(TestUtils.equals(options, optionsOut));
+ assertNotNull(result);
+
+ int fromIndex = (page - 1) * pageSize;
+ int toIndex = Math.min(page * pageSize,
+ MockMediaLibraryService2.GET_CHILDREN_RESULT.size());
+
+ // Compare the given results with originals.
+ for (int originalIndex = fromIndex; originalIndex < toIndex; originalIndex++) {
+ int relativeIndex = originalIndex - fromIndex;
+ assertEquals(
+ MockMediaLibraryService2.GET_CHILDREN_RESULT.get(originalIndex)
+ .getMediaId(),
+ result.get(relativeIndex).getMediaId());
+ }
+ latch.countDown();
+ }
+ };
+
+ final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+ MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+ browser.getChildren(parentId, page, pageSize, options);
+ assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testGetChildrenEmptyResult() throws InterruptedException {
+ final String parentId = MockMediaLibraryService2.PARENT_ID_NO_CHILDREN;
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ final TestControllerCallbackInterface callback = new TestBrowserCallbackInterface() {
+ @Override
+ public void onChildrenLoaded(String parentIdOut, int pageOut, int pageSizeOut,
+ Bundle optionsOut, List<MediaItem2> result) {
+ assertNotNull(result);
+ assertEquals(0, result.size());
+ latch.countDown();
+ }
+ };
+
+ final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+ MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+ browser.getChildren(parentId, 1, 1, null);
+ assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testGetChildrenNullResult() throws InterruptedException {
+ final String parentId = MockMediaLibraryService2.PARENT_ID_ERROR;
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ final TestControllerCallbackInterface callback = new TestBrowserCallbackInterface() {
+ @Override
+ public void onChildrenLoaded(String parentIdOut, int pageOut, int pageSizeOut,
+ Bundle optionsOut, List<MediaItem2> result) {
+ assertNull(result);
+ latch.countDown();
+ }
+ };
+
+ final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+ MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+ browser.getChildren(parentId, 1, 1, null);
+ assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ }
+
public static class TestBrowserCallback extends BrowserCallback
implements WaitForConnectionInterface {
private final TestControllerCallbackInterface mCallbackProxy;
@@ -151,6 +279,24 @@
}
@Override
+ public void onItemLoaded(String mediaId, MediaItem2 result) {
+ super.onItemLoaded(mediaId, result);
+ if (mCallbackProxy instanceof TestBrowserCallbackInterface) {
+ ((TestBrowserCallbackInterface) mCallbackProxy).onItemLoaded(mediaId, result);
+ }
+ }
+
+ @Override
+ public void onChildrenLoaded(String parentId, int page, int pageSize, Bundle options,
+ List<MediaItem2> result) {
+ super.onChildrenLoaded(parentId, page, pageSize, options, result);
+ if (mCallbackProxy instanceof TestBrowserCallbackInterface) {
+ ((TestBrowserCallbackInterface) mCallbackProxy)
+ .onChildrenLoaded(parentId, page, pageSize, options, result);
+ }
+ }
+
+ @Override
public void waitForConnect(boolean expect) throws InterruptedException {
if (expect) {
assertTrue(connectLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
diff --git a/packages/MediaComponents/test/src/android/media/MediaController2Test.java b/packages/MediaComponents/test/src/android/media/MediaController2Test.java
index 07baf58..7bf0fd2 100644
--- a/packages/MediaComponents/test/src/android/media/MediaController2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaController2Test.java
@@ -21,9 +21,11 @@
import android.content.Intent;
import android.media.MediaPlayerInterface.PlaybackListener;
import android.media.MediaSession2.Command;
+import android.media.MediaSession2.CommandGroup;
import android.media.MediaSession2.ControllerInfo;
import android.media.MediaSession2.PlaylistParams;
import android.media.MediaSession2.SessionCallback;
+import android.media.TestServiceRegistry.SessionCallbackProxy;
import android.media.TestUtils.SyncHandler;
import android.net.Uri;
import android.os.Bundle;
@@ -34,6 +36,7 @@
import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.text.TextUtils;
import org.junit.After;
import org.junit.Before;
@@ -618,24 +621,32 @@
@Ignore
@Test
public void testConnectToService_sessionService() throws InterruptedException {
- connectToService(TestUtils.getServiceToken(mContext, MockMediaSessionService2.ID));
- testConnectToService();
+ testConnectToService(MockMediaSessionService2.ID);
}
// TODO(jaewan): Reenable when session manager detects app installs
@Ignore
@Test
public void testConnectToService_libraryService() throws InterruptedException {
- connectToService(TestUtils.getServiceToken(mContext, MockMediaLibraryService2.ID));
- testConnectToService();
+ testConnectToService(MockMediaLibraryService2.ID);
}
- public void testConnectToService() throws InterruptedException {
- TestServiceRegistry serviceInfo = TestServiceRegistry.getInstance();
- ControllerInfo info = serviceInfo.getOnConnectControllerInfo();
- assertEquals(mContext.getPackageName(), info.getPackageName());
- assertEquals(Process.myUid(), info.getUid());
- assertFalse(info.isTrusted());
+ public void testConnectToService(String id) throws InterruptedException {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final SessionCallbackProxy proxy = new SessionCallbackProxy(mContext) {
+ @Override
+ public CommandGroup onConnect(ControllerInfo controller) {
+ if (Process.myUid() == controller.getUid()) {
+ assertEquals(mContext.getPackageName(), controller.getPackageName());
+ assertFalse(controller.isTrusted());
+ latch.countDown();;
+ }
+ return super.onConnect(controller);
+ }
+ };
+ TestServiceRegistry.getInstance().setSessionCallbackProxy(proxy);
+ mController = createController(TestUtils.getServiceToken(mContext, id));
+ assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
// Test command from controller to session service
mController.play();
@@ -701,27 +712,26 @@
@Ignore
@Test
public void testClose_sessionService() throws InterruptedException {
- connectToService(TestUtils.getServiceToken(mContext, MockMediaSessionService2.ID));
- testCloseFromService();
+ testCloseFromService(MockMediaSessionService2.ID);
}
// TODO(jaewan): Reenable when session manager detects app installs
@Ignore
@Test
public void testClose_libraryService() throws InterruptedException {
- connectToService(TestUtils.getServiceToken(mContext, MockMediaSessionService2.ID));
- testCloseFromService();
+ testCloseFromService(MockMediaLibraryService2.ID);
}
- private void testCloseFromService() throws InterruptedException {
- final String id = mController.getSessionToken().getId();
+ private void testCloseFromService(String id) throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(1);
- TestServiceRegistry.getInstance().setServiceInstanceChangedCallback((service) -> {
- if (service == null) {
- // Destroying..
+ final SessionCallbackProxy proxy = new SessionCallbackProxy(mContext) {
+ @Override
+ public void onServiceDestroyed() {
latch.countDown();
}
- });
+ };
+ TestServiceRegistry.getInstance().setSessionCallbackProxy(proxy);
+ mController = createController(TestUtils.getServiceToken(mContext, id));
mController.close();
// Wait until close triggers onDestroy() of the session service.
assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
diff --git a/packages/MediaComponents/test/src/android/media/MockMediaLibraryService2.java b/packages/MediaComponents/test/src/android/media/MockMediaLibraryService2.java
index ec69ff6..5fabebc 100644
--- a/packages/MediaComponents/test/src/android/media/MockMediaLibraryService2.java
+++ b/packages/MediaComponents/test/src/android/media/MockMediaLibraryService2.java
@@ -23,9 +23,17 @@
import android.content.Context;
import android.media.MediaSession2.CommandGroup;
import android.media.MediaSession2.ControllerInfo;
+import android.media.TestServiceRegistry.SessionCallbackProxy;
import android.media.TestUtils.SyncHandler;
import android.os.Bundle;
import android.os.Process;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.util.ArrayList;
+import java.util.List;
+
+import java.util.concurrent.Executor;
import javax.annotation.concurrent.GuardedBy;
@@ -38,6 +46,20 @@
public static final String ROOT_ID = "rootId";
public static final Bundle EXTRA = new Bundle();
+
+ public static final String MEDIA_ID_GET_ITEM = "media_id_get_item";
+
+ public static final String PARENT_ID = "parent_id";
+ public static final String PARENT_ID_NO_CHILDREN = "parent_id_no_children";
+ public static final String PARENT_ID_ERROR = "parent_id_error";
+ public static final List<MediaItem2> GET_CHILDREN_RESULT = new ArrayList<>();
+
+ private static final int CHILDREN_COUNT = 100;
+ private static final DataSourceDesc DATA_SOURCE_DESC =
+ new DataSourceDesc.Builder().setDataSource(new FileDescriptor()).build();
+
+ private static final String TAG = "MockMediaLibrarySvc2";
+
static {
EXTRA.putString(ROOT_ID, ROOT_ID);
}
@@ -46,20 +68,36 @@
private MediaLibrarySession mSession;
+ public MockMediaLibraryService2() {
+ super();
+ GET_CHILDREN_RESULT.clear();
+ String mediaIdPrefix = "media_id_";
+ for (int i = 0; i < CHILDREN_COUNT; i++) {
+ GET_CHILDREN_RESULT.add(createMediaItem(mediaIdPrefix + i));
+ }
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ TestServiceRegistry.getInstance().setServiceInstance(this);
+ }
+
@Override
public MediaLibrarySession onCreateSession(String sessionId) {
final MockPlayer player = new MockPlayer(1);
final SyncHandler handler = (SyncHandler) TestServiceRegistry.getInstance().getHandler();
- try {
- handler.postAndSync(() -> {
- TestLibrarySessionCallback callback = new TestLibrarySessionCallback();
- mSession = new MediaLibrarySessionBuilder(MockMediaLibraryService2.this,
- player, (runnable) -> handler.post(runnable), callback)
- .setId(sessionId).build();
- });
- } catch (InterruptedException e) {
- fail(e.toString());
+ final Executor executor = (runnable) -> handler.post(runnable);
+ SessionCallbackProxy sessionCallbackProxy = TestServiceRegistry.getInstance()
+ .getSessionCallbackProxy();
+ if (sessionCallbackProxy == null) {
+ // Ensures non-null
+ sessionCallbackProxy = new SessionCallbackProxy(this) {};
}
+ TestLibrarySessionCallback callback =
+ new TestLibrarySessionCallback(sessionCallbackProxy);
+ mSession = new MediaLibrarySessionBuilder(MockMediaLibraryService2.this, player,
+ executor, callback).setId(sessionId).build();
return mSession;
}
@@ -81,24 +119,76 @@
}
private class TestLibrarySessionCallback extends MediaLibrarySessionCallback {
- public TestLibrarySessionCallback() {
+ private final SessionCallbackProxy mCallbackProxy;
+
+ public TestLibrarySessionCallback(SessionCallbackProxy callbackProxy) {
super(MockMediaLibraryService2.this);
+ mCallbackProxy = callbackProxy;
}
@Override
public CommandGroup onConnect(ControllerInfo controller) {
- if (Process.myUid() != controller.getUid()) {
- // It's system app wants to listen changes. Ignore.
- return super.onConnect(controller);
- }
- TestServiceRegistry.getInstance().setServiceInstance(
- MockMediaLibraryService2.this, controller);
- return super.onConnect(controller);
+ return mCallbackProxy.onConnect(controller);
}
@Override
public LibraryRoot onGetRoot(ControllerInfo controller, Bundle rootHints) {
return new LibraryRoot(MockMediaLibraryService2.this, ROOT_ID, EXTRA);
}
+
+ @Override
+ public MediaItem2 onLoadItem(ControllerInfo controller, String mediaId) {
+ if (MEDIA_ID_GET_ITEM.equals(mediaId)) {
+ return createMediaItem(mediaId);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public List<MediaItem2> onLoadChildren(ControllerInfo controller, String parentId, int page,
+ int pageSize, Bundle options) {
+ if (PARENT_ID.equals(parentId)) {
+ return getPaginatedResult(GET_CHILDREN_RESULT, page, pageSize);
+ } else if (PARENT_ID_ERROR.equals(parentId)) {
+ return null;
+ }
+ // Includes the case of PARENT_ID_NO_CHILDREN.
+ return new ArrayList<>();
+ }
+ }
+
+ private List<MediaItem2> getPaginatedResult(List<MediaItem2> items, int page, int pageSize) {
+ if (items == null) {
+ return null;
+ } else if (items.size() == 0) {
+ return new ArrayList<>();
+ }
+
+ final int totalItemCount = items.size();
+ int fromIndex = (page - 1) * pageSize;
+ int toIndex = Math.min(page * pageSize, totalItemCount);
+
+ List<MediaItem2> paginatedResult = new ArrayList<>();
+ try {
+ // The case of (fromIndex >= totalItemCount) will throw exception below.
+ paginatedResult = items.subList(fromIndex, toIndex);
+ } catch (IndexOutOfBoundsException | IllegalArgumentException ex) {
+ Log.d(TAG, "Result is empty for given pagination arguments: totalItemCount="
+ + totalItemCount + ", page=" + page + ", pageSize=" + pageSize, ex);
+ }
+ return paginatedResult;
+ }
+
+ private MediaItem2 createMediaItem(String mediaId) {
+ Context context = MockMediaLibraryService2.this;
+ return new MediaItem2(
+ context,
+ mediaId,
+ DATA_SOURCE_DESC,
+ new MediaMetadata2.Builder(context)
+ .putString(MediaMetadata2.METADATA_KEY_MEDIA_ID, mediaId)
+ .build(),
+ 0 /* Flags */);
}
}
\ No newline at end of file
diff --git a/packages/MediaComponents/test/src/android/media/MockMediaSessionService2.java b/packages/MediaComponents/test/src/android/media/MockMediaSessionService2.java
index c8ed184..12c2c9f 100644
--- a/packages/MediaComponents/test/src/android/media/MockMediaSessionService2.java
+++ b/packages/MediaComponents/test/src/android/media/MockMediaSessionService2.java
@@ -22,11 +22,11 @@
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
+import android.media.MediaSession2.CommandGroup;
import android.media.MediaSession2.ControllerInfo;
import android.media.MediaSession2.SessionCallback;
+import android.media.TestServiceRegistry.SessionCallbackProxy;
import android.media.TestUtils.SyncHandler;
-import android.media.session.PlaybackState;
-import android.os.Process;
import java.util.concurrent.Executor;
@@ -45,29 +45,32 @@
private NotificationManager mNotificationManager;
@Override
+ public void onCreate() {
+ super.onCreate();
+ TestServiceRegistry.getInstance().setServiceInstance(this);
+ mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+
+ @Override
public MediaSession2 onCreateSession(String sessionId) {
final MockPlayer player = new MockPlayer(1);
final SyncHandler handler = (SyncHandler) TestServiceRegistry.getInstance().getHandler();
final Executor executor = (runnable) -> handler.post(runnable);
- try {
- handler.postAndSync(() -> {
- mSession = new MediaSession2.Builder(MockMediaSessionService2.this, player)
- .setSessionCallback(executor, new MySessionCallback())
- .setId(sessionId).build();
- });
- } catch (InterruptedException e) {
- fail(e.toString());
+ SessionCallbackProxy sessionCallbackProxy = TestServiceRegistry.getInstance()
+ .getSessionCallbackProxy();
+ if (sessionCallbackProxy == null) {
+ // Ensures non-null
+ sessionCallbackProxy = new SessionCallbackProxy(this) {};
}
+ TestSessionServiceCallback callback =
+ new TestSessionServiceCallback(sessionCallbackProxy);
+ mSession = new MediaSession2.Builder(this, player)
+ .setSessionCallback(executor, callback)
+ .setId(sessionId).build();
return mSession;
}
@Override
- public void onCreate() {
- super.onCreate();
- mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- }
-
- @Override
public void onDestroy() {
TestServiceRegistry.getInstance().cleanUp();
super.onDestroy();
@@ -90,20 +93,17 @@
return new MediaNotification(this, DEFAULT_MEDIA_NOTIFICATION_ID, notification);
}
- private class MySessionCallback extends SessionCallback {
- public MySessionCallback() {
+ private class TestSessionServiceCallback extends SessionCallback {
+ private final SessionCallbackProxy mCallbackProxy;
+
+ public TestSessionServiceCallback(SessionCallbackProxy callbackProxy) {
super(MockMediaSessionService2.this);
+ mCallbackProxy = callbackProxy;
}
@Override
- public MediaSession2.CommandGroup onConnect(ControllerInfo controller) {
- if (Process.myUid() != controller.getUid()) {
- // It's system app wants to listen changes. Ignore.
- return super.onConnect(controller);
- }
- TestServiceRegistry.getInstance().setServiceInstance(
- MockMediaSessionService2.this, controller);
- return super.onConnect(controller);
+ public CommandGroup onConnect(ControllerInfo controller) {
+ return mCallbackProxy.onConnect(controller);
}
}
}
diff --git a/packages/MediaComponents/test/src/android/media/SessionToken2Test.java b/packages/MediaComponents/test/src/android/media/SessionToken2Test.java
new file mode 100644
index 0000000..efde78a
--- /dev/null
+++ b/packages/MediaComponents/test/src/android/media/SessionToken2Test.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 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.
+ */
+
+package android.media;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.content.Context;
+import android.os.Process;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests {@link SessionToken2}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SessionToken2Test {
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getTargetContext();
+ }
+
+ @Test
+ public void testConstructor_sessionService() {
+ SessionToken2 token = new SessionToken2(mContext, mContext.getPackageName(),
+ MockMediaSessionService2.class.getCanonicalName());
+ assertEquals(MockMediaSessionService2.ID, token.getId());
+ assertEquals(mContext.getPackageName(), token.getPackageName());
+ assertEquals(Process.myUid(), token.getUid());
+ assertEquals(SessionToken2.TYPE_SESSION_SERVICE, token.getType());
+ }
+
+ @Test
+ public void testConstructor_libraryService() {
+ SessionToken2 token = new SessionToken2(mContext, mContext.getPackageName(),
+ MockMediaLibraryService2.class.getCanonicalName());
+ assertEquals(MockMediaLibraryService2.ID, token.getId());
+ assertEquals(mContext.getPackageName(), token.getPackageName());
+ assertEquals(Process.myUid(), token.getUid());
+ assertEquals(SessionToken2.TYPE_LIBRARY_SERVICE, token.getType());
+ }
+}
\ No newline at end of file
diff --git a/packages/MediaComponents/test/src/android/media/TestServiceRegistry.java b/packages/MediaComponents/test/src/android/media/TestServiceRegistry.java
index 6f5512e..3800c28 100644
--- a/packages/MediaComponents/test/src/android/media/TestServiceRegistry.java
+++ b/packages/MediaComponents/test/src/android/media/TestServiceRegistry.java
@@ -18,10 +18,12 @@
import static org.junit.Assert.fail;
+import android.content.Context;
+import android.media.MediaSession2.CommandGroup;
import android.media.MediaSession2.ControllerInfo;
import android.media.TestUtils.SyncHandler;
import android.os.Handler;
-import android.os.Looper;
+import android.os.Process;
import android.support.annotation.GuardedBy;
/**
@@ -31,8 +33,46 @@
* It only support only one service at a time.
*/
public class TestServiceRegistry {
- public interface ServiceInstanceChangedCallback {
- void OnServiceInstanceChanged(MediaSessionService2 service);
+ /**
+ * Proxy for both {@link MediaSession2.SessionCallback} and
+ * {@link MediaLibraryService2.MediaLibrarySessionCallback}.
+ */
+ public static abstract class SessionCallbackProxy {
+ private final Context mContext;
+
+ /**
+ * Constructor
+ */
+ public SessionCallbackProxy(Context context) {
+ mContext = context;
+ }
+
+ public final Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * @param controller
+ * @return
+ */
+ public CommandGroup onConnect(ControllerInfo controller) {
+ if (Process.myUid() == controller.getUid()) {
+ CommandGroup commands = new CommandGroup(mContext);
+ commands.addAllPredefinedCommands();
+ return commands;
+ }
+ return null;
+ }
+
+ /**
+ * Called when enclosing service is created.
+ */
+ public void onServiceCreated(MediaSessionService2 service) { }
+
+ /**
+ * Called when enclosing service is destroyed.
+ */
+ public void onServiceDestroyed() { }
}
@GuardedBy("TestServiceRegistry.class")
@@ -42,9 +82,7 @@
@GuardedBy("TestServiceRegistry.class")
private SyncHandler mHandler;
@GuardedBy("TestServiceRegistry.class")
- private ControllerInfo mOnConnectControllerInfo;
- @GuardedBy("TestServiceRegistry.class")
- private ServiceInstanceChangedCallback mCallback;
+ private SessionCallbackProxy mCallbackProxy;
public static TestServiceRegistry getInstance() {
synchronized (TestServiceRegistry.class) {
@@ -61,28 +99,33 @@
}
}
- public void setServiceInstanceChangedCallback(ServiceInstanceChangedCallback callback) {
- synchronized (TestServiceRegistry.class) {
- mCallback = callback;
- }
- }
-
public Handler getHandler() {
synchronized (TestServiceRegistry.class) {
return mHandler;
}
}
- public void setServiceInstance(MediaSessionService2 service, ControllerInfo controller) {
+ public void setSessionCallbackProxy(SessionCallbackProxy callbackProxy) {
+ synchronized (TestServiceRegistry.class) {
+ mCallbackProxy = callbackProxy;
+ }
+ }
+
+ public SessionCallbackProxy getSessionCallbackProxy() {
+ synchronized (TestServiceRegistry.class) {
+ return mCallbackProxy;
+ }
+ }
+
+ public void setServiceInstance(MediaSessionService2 service) {
synchronized (TestServiceRegistry.class) {
if (mService != null) {
fail("Previous service instance is still running. Clean up manually to ensure"
+ " previoulsy running service doesn't break current test");
}
mService = service;
- mOnConnectControllerInfo = controller;
- if (mCallback != null) {
- mCallback.OnServiceInstanceChanged(service);
+ if (mCallbackProxy != null) {
+ mCallbackProxy.onServiceCreated(service);
}
}
}
@@ -93,28 +136,11 @@
}
}
- public ControllerInfo getOnConnectControllerInfo() {
- synchronized (TestServiceRegistry.class) {
- return mOnConnectControllerInfo;
- }
- }
-
-
public void cleanUp() {
synchronized (TestServiceRegistry.class) {
- final ServiceInstanceChangedCallback callback = mCallback;
+ final SessionCallbackProxy callbackProxy = mCallbackProxy;
if (mService != null) {
- try {
- if (mHandler.getLooper() == Looper.myLooper()) {
- mService.getSession().close();
- } else {
- mHandler.postAndSync(() -> {
- mService.getSession().close();
- });
- }
- } catch (InterruptedException e) {
- // No-op. Service containing session will die, but shouldn't be a huge issue.
- }
+ mService.getSession().close();
// stopSelf() would not kill service while the binder connection established by
// bindService() exists, and close() above will do the job instead.
// So stopSelf() isn't really needed, but just for sure.
@@ -124,11 +150,10 @@
if (mHandler != null) {
mHandler.removeCallbacksAndMessages(null);
}
- mCallback = null;
- mOnConnectControllerInfo = null;
+ mCallbackProxy = null;
- if (callback != null) {
- callback.OnServiceInstanceChanged(null);
+ if (callbackProxy != null) {
+ callbackProxy.onServiceDestroyed();
}
}
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 794aae2..afd23a6 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1158,6 +1158,12 @@
bool force = !outputDesc->isActive() &&
(outputDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE);
+ // requiresMuteCheck is false when we can bypass mute strategy.
+ // It covers a common case when there is no materially active audio
+ // and muting would result in unnecessary delay and dropped audio.
+ const uint32_t outputLatencyMs = outputDesc->latency();
+ bool requiresMuteCheck = outputDesc->isActive(outputLatencyMs * 2); // account for drain
+
// increment usage count for this stream on the requested output:
// NOTE that the usage count is the same for duplicated output and hardware output which is
// necessary for a correct control of hardware output routing by startOutput() and stopOutput()
@@ -1181,29 +1187,44 @@
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
if (desc != outputDesc) {
+ // An output has a shared device if
+ // - managed by the same hw module
+ // - supports the currently selected device
+ const bool sharedDevice = outputDesc->sharesHwModuleWith(desc)
+ && (desc->supportedDevices() & device) != AUDIO_DEVICE_NONE;
+
// force a device change if any other output is:
// - managed by the same hw module
- // - has a current device selection that differs from selected device.
// - supports currently selected device
+ // - has a current device selection that differs from selected device.
// - has an active audio patch
// In this case, the audio HAL must receive the new device selection so that it can
- // change the device currently selected by the other active output.
- if (outputDesc->sharesHwModuleWith(desc) &&
+ // change the device currently selected by the other output.
+ if (sharedDevice &&
desc->device() != device &&
- desc->supportedDevices() & device &&
desc->getPatchHandle() != AUDIO_PATCH_HANDLE_NONE) {
force = true;
}
// wait for audio on other active outputs to be presented when starting
// a notification so that audio focus effect can propagate, or that a mute/unmute
// event occurred for beacon
- uint32_t latency = desc->latency();
- if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {
- waitMs = latency;
+ const uint32_t latencyMs = desc->latency();
+ const bool isActive = desc->isActive(latencyMs * 2); // account for drain
+
+ if (shouldWait && isActive && (waitMs < latencyMs)) {
+ waitMs = latencyMs;
}
+
+ // Require mute check if another output is on a shared device
+ // and currently active to have proper drain and avoid pops.
+ // Note restoring AudioTracks onto this output needs to invoke
+ // a volume ramp if there is no mute.
+ requiresMuteCheck |= sharedDevice && isActive;
}
}
- uint32_t muteWaitMs = setOutputDevice(outputDesc, device, force, 0, NULL, address);
+
+ const uint32_t muteWaitMs =
+ setOutputDevice(outputDesc, device, force, 0, NULL, address, requiresMuteCheck);
// handle special case for sonification while in call
if (isInCall()) {
@@ -1228,6 +1249,14 @@
if (waitMs > muteWaitMs) {
*delayMs = waitMs - muteWaitMs;
}
+
+ // FIXME: A device change (muteWaitMs > 0) likely introduces a volume change.
+ // A volume change enacted by APM with 0 delay is not synchronous, as it goes
+ // via AudioCommandThread to AudioFlinger. Hence it is possible that the volume
+ // change occurs after the MixerThread starts and causes a stream volume
+ // glitch.
+ //
+ // We do not introduce additional delay here.
}
return NO_ERROR;
@@ -4735,21 +4764,24 @@
bool force,
int delayMs,
audio_patch_handle_t *patchHandle,
- const char* address)
+ const char *address,
+ bool requiresMuteCheck)
{
ALOGV("setOutputDevice() device %04x delayMs %d", device, delayMs);
AudioParameter param;
uint32_t muteWaitMs;
if (outputDesc->isDuplicated()) {
- muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs);
- muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs);
+ muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs,
+ nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
+ muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs,
+ nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
return muteWaitMs;
}
// no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
// output profile
if ((device != AUDIO_DEVICE_NONE) &&
- ((device & outputDesc->supportedDevices()) == 0)) {
+ ((device & outputDesc->supportedDevices()) == AUDIO_DEVICE_NONE)) {
return 0;
}
@@ -4763,7 +4795,14 @@
if (device != AUDIO_DEVICE_NONE) {
outputDesc->mDevice = device;
}
- muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+
+ // if the outputs are not materially active, there is no need to mute.
+ if (requiresMuteCheck) {
+ muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+ } else {
+ ALOGV("%s: suppressing checkDeviceMuteStrategies", __func__);
+ muteWaitMs = 0;
+ }
// Do not change the routing if:
// the requested device is AUDIO_DEVICE_NONE
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index ee339e7..2b68882 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -317,7 +317,8 @@
bool force = false,
int delayMs = 0,
audio_patch_handle_t *patchHandle = NULL,
- const char* address = NULL);
+ const char *address = nullptr,
+ bool requiresMuteCheck = true);
status_t resetOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
int delayMs = 0,
audio_patch_handle_t *patchHandle = NULL);
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 7fe363d..c7dfe0f 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -399,11 +399,12 @@
while (pos + size > *totSize) {
*totSize += ((*totSize + 7) / 8) * 4;
}
- *param = (char *)realloc(*param, *totSize);
- if (*param == NULL) {
+ char *newParam = (char *)realloc(*param, *totSize);
+ if (newParam == NULL) {
ALOGE("%s realloc error for size %zu", __func__, *totSize);
return 0;
}
+ *param = newParam;
}
*curSize = pos + size;
return pos;
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp
index e06a81f..394701a 100644
--- a/services/camera/libcameraservice/CameraFlashlight.cpp
+++ b/services/camera/libcameraservice/CameraFlashlight.cpp
@@ -32,13 +32,15 @@
namespace android {
+using hardware::camera::common::V1_0::TorchModeStatus;
+
/////////////////////////////////////////////////////////////////////
// CameraFlashlight implementation begins
// used by camera service to control flashflight.
/////////////////////////////////////////////////////////////////////
CameraFlashlight::CameraFlashlight(sp<CameraProviderManager> providerManager,
- camera_module_callbacks_t* callbacks) :
+ CameraProviderManager::StatusListener* callbacks) :
mProviderManager(providerManager),
mCallbacks(callbacks),
mFlashlightMapInitialized(false) {
@@ -59,7 +61,7 @@
} else {
// Only HAL1 devices do not support setTorchMode
mFlashControl =
- new CameraHardwareInterfaceFlashControl(mProviderManager, *mCallbacks);
+ new CameraHardwareInterfaceFlashControl(mProviderManager, mCallbacks);
}
return OK;
@@ -119,7 +121,8 @@
}
int CameraFlashlight::getNumberOfCameras() {
- return mProviderManager->getAPI1CompatibleCameraCount();
+ size_t len = mProviderManager->getAPI1CompatibleCameraDeviceIds().size();
+ return static_cast<int>(len);
}
status_t CameraFlashlight::findFlashUnits() {
@@ -221,9 +224,8 @@
int numCameras = getNumberOfCameras();
for (int i = 0; i < numCameras; i++) {
if (hasFlashUnitLocked(String8::format("%d", i))) {
- mCallbacks->torch_mode_status_change(mCallbacks,
- String8::format("%d", i).string(),
- TORCH_MODE_STATUS_NOT_AVAILABLE);
+ mCallbacks->onTorchStatusChanged(
+ String8::format("%d", i), TorchModeStatus::NOT_AVAILABLE);
}
}
}
@@ -266,9 +268,8 @@
int numCameras = getNumberOfCameras();
for (int i = 0; i < numCameras; i++) {
if (hasFlashUnitLocked(String8::format("%d", i))) {
- mCallbacks->torch_mode_status_change(mCallbacks,
- String8::format("%d", i).string(),
- TORCH_MODE_STATUS_AVAILABLE_OFF);
+ mCallbacks->onTorchStatusChanged(
+ String8::format("%d", i), TorchModeStatus::AVAILABLE_OFF);
}
}
}
@@ -315,9 +316,9 @@
CameraHardwareInterfaceFlashControl::CameraHardwareInterfaceFlashControl(
sp<CameraProviderManager> manager,
- const camera_module_callbacks_t& callbacks) :
+ CameraProviderManager::StatusListener* callbacks) :
mProviderManager(manager),
- mCallbacks(&callbacks),
+ mCallbacks(callbacks),
mTorchEnabled(false) {
}
@@ -333,8 +334,7 @@
if (mCallbacks) {
ALOGV("%s: notify the framework that torch was turned off",
__FUNCTION__);
- mCallbacks->torch_mode_status_change(mCallbacks,
- mCameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
+ mCallbacks->onTorchStatusChanged(mCameraId, TorchModeStatus::AVAILABLE_OFF);
}
}
}
@@ -368,8 +368,7 @@
// disabling the torch mode of currently opened device
disconnectCameraDevice();
mTorchEnabled = false;
- mCallbacks->torch_mode_status_change(mCallbacks,
- cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
+ mCallbacks->onTorchStatusChanged(cameraId, TorchModeStatus::AVAILABLE_OFF);
return OK;
}
@@ -379,8 +378,7 @@
}
mTorchEnabled = true;
- mCallbacks->torch_mode_status_change(mCallbacks,
- cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_ON);
+ mCallbacks->onTorchStatusChanged(cameraId, TorchModeStatus::AVAILABLE_ON);
return OK;
}
diff --git a/services/camera/libcameraservice/CameraFlashlight.h b/services/camera/libcameraservice/CameraFlashlight.h
index c86ee85..07ce829 100644
--- a/services/camera/libcameraservice/CameraFlashlight.h
+++ b/services/camera/libcameraservice/CameraFlashlight.h
@@ -19,7 +19,6 @@
#include <gui/GLConsumer.h>
#include <gui/Surface.h>
-#include <hardware/camera_common.h>
#include <utils/KeyedVector.h>
#include <utils/SortedVector.h>
#include "common/CameraProviderManager.h"
@@ -55,7 +54,7 @@
class CameraFlashlight : public virtual VirtualLightRefBase {
public:
CameraFlashlight(sp<CameraProviderManager> providerManager,
- camera_module_callbacks_t* callbacks);
+ CameraProviderManager::StatusListener* callbacks);
virtual ~CameraFlashlight();
// Find all flash units. This must be called before other methods. All
@@ -99,7 +98,7 @@
sp<CameraProviderManager> mProviderManager;
- const camera_module_callbacks_t *mCallbacks;
+ CameraProviderManager::StatusListener* mCallbacks;
SortedVector<String8> mOpenedCameraIds;
// camera id -> if it has a flash unit
@@ -134,7 +133,7 @@
public:
CameraHardwareInterfaceFlashControl(
sp<CameraProviderManager> manager,
- const camera_module_callbacks_t& callbacks);
+ CameraProviderManager::StatusListener* callbacks);
virtual ~CameraHardwareInterfaceFlashControl();
// FlashControlBase
@@ -166,7 +165,7 @@
status_t hasFlashUnitLocked(const String8& cameraId, bool *hasFlash, bool keepDeviceOpen);
sp<CameraProviderManager> mProviderManager;
- const camera_module_callbacks_t *mCallbacks;
+ CameraProviderManager::StatusListener* mCallbacks;
sp<CameraHardwareInterface> mDevice;
String8 mCameraId;
CameraParameters mParameters;
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index e7609ed..89ca6bb 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -107,79 +107,13 @@
// ----------------------------------------------------------------------------
-extern "C" {
-static void camera_device_status_change(
- const struct camera_module_callbacks* callbacks,
- int camera_id,
- int new_status) {
- sp<CameraService> cs = const_cast<CameraService*>(
- static_cast<const CameraService*>(callbacks));
- String8 id = String8::format("%d", camera_id);
-
- CameraDeviceStatus newStatus{CameraDeviceStatus::NOT_PRESENT};
- switch (new_status) {
- case CAMERA_DEVICE_STATUS_NOT_PRESENT:
- newStatus = CameraDeviceStatus::NOT_PRESENT;
- break;
- case CAMERA_DEVICE_STATUS_PRESENT:
- newStatus = CameraDeviceStatus::PRESENT;
- break;
- case CAMERA_DEVICE_STATUS_ENUMERATING:
- newStatus = CameraDeviceStatus::ENUMERATING;
- break;
- default:
- ALOGW("Unknown device status change to %d", new_status);
- break;
- }
- cs->onDeviceStatusChanged(id, newStatus);
-}
-
-static void torch_mode_status_change(
- const struct camera_module_callbacks* callbacks,
- const char* camera_id,
- int new_status) {
- if (!callbacks || !camera_id) {
- ALOGE("%s invalid parameters. callbacks %p, camera_id %p", __FUNCTION__,
- callbacks, camera_id);
- }
- sp<CameraService> cs = const_cast<CameraService*>(
- static_cast<const CameraService*>(callbacks));
-
- TorchModeStatus status;
- switch (new_status) {
- case TORCH_MODE_STATUS_NOT_AVAILABLE:
- status = TorchModeStatus::NOT_AVAILABLE;
- break;
- case TORCH_MODE_STATUS_AVAILABLE_OFF:
- status = TorchModeStatus::AVAILABLE_OFF;
- break;
- case TORCH_MODE_STATUS_AVAILABLE_ON:
- status = TorchModeStatus::AVAILABLE_ON;
- break;
- default:
- ALOGE("Unknown torch status %d", new_status);
- return;
- }
-
- cs->onTorchStatusChanged(
- String8(camera_id),
- status);
-}
-} // extern "C"
-
-// ----------------------------------------------------------------------------
-
static const String16 sManageCameraPermission("android.permission.MANAGE_CAMERA");
CameraService::CameraService() :
mEventLog(DEFAULT_EVENT_LOG_LENGTH),
- mNumberOfCameras(0), mNumberOfNormalCameras(0),
+ mNumberOfCameras(0),
mSoundRef(0), mInitialized(false) {
ALOGI("CameraService started (pid=%d)", getpid());
-
- this->camera_device_status_change = android::camera_device_status_change;
- this->torch_mode_status_change = android::torch_mode_status_change;
-
mServiceLockWrapper = std::make_shared<WaitableMutexWrapper>(&mServiceLock);
}
@@ -209,52 +143,42 @@
status_t CameraService::enumerateProviders() {
status_t res;
- Mutex::Autolock l(mServiceLock);
- if (nullptr == mCameraProviderManager.get()) {
- mCameraProviderManager = new CameraProviderManager();
- res = mCameraProviderManager->initialize(this);
- if (res != OK) {
- ALOGE("%s: Unable to initialize camera provider manager: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
- }
+ std::vector<std::string> deviceIds;
+ {
+ Mutex::Autolock l(mServiceLock);
- mNumberOfCameras = mCameraProviderManager->getCameraCount();
- mNumberOfNormalCameras =
- mCameraProviderManager->getAPI1CompatibleCameraCount();
-
- // Setup vendor tags before we call get_camera_info the first time
- // because HAL might need to setup static vendor keys in get_camera_info
- // TODO: maybe put this into CameraProviderManager::initialize()?
- mCameraProviderManager->setUpVendorTags();
-
- if (nullptr == mFlashlight.get()) {
- mFlashlight = new CameraFlashlight(mCameraProviderManager, this);
- }
-
- res = mFlashlight->findFlashUnits();
- if (res != OK) {
- ALOGE("Failed to enumerate flash units: %s (%d)", strerror(-res), res);
- }
-
- for (auto& cameraId : mCameraProviderManager->getCameraDeviceIds()) {
- String8 id8 = String8(cameraId.c_str());
- bool cameraFound = false;
- {
-
- Mutex::Autolock lock(mCameraStatesLock);
- auto iter = mCameraStates.find(id8);
- if (iter != mCameraStates.end()) {
- cameraFound = true;
+ if (nullptr == mCameraProviderManager.get()) {
+ mCameraProviderManager = new CameraProviderManager();
+ res = mCameraProviderManager->initialize(this);
+ if (res != OK) {
+ ALOGE("%s: Unable to initialize camera provider manager: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
}
}
- if (!cameraFound) {
- addStates(id8);
+
+ // Setup vendor tags before we call get_camera_info the first time
+ // because HAL might need to setup static vendor keys in get_camera_info
+ // TODO: maybe put this into CameraProviderManager::initialize()?
+ mCameraProviderManager->setUpVendorTags();
+
+ if (nullptr == mFlashlight.get()) {
+ mFlashlight = new CameraFlashlight(mCameraProviderManager, this);
}
+ res = mFlashlight->findFlashUnits();
+ if (res != OK) {
+ ALOGE("Failed to enumerate flash units: %s (%d)", strerror(-res), res);
+ }
+
+ deviceIds = mCameraProviderManager->getCameraDeviceIds();
+ }
+
+
+ for (auto& cameraId : deviceIds) {
+ String8 id8 = String8(cameraId.c_str());
onDeviceStatusChanged(id8, CameraDeviceStatus::PRESENT);
}
@@ -291,6 +215,13 @@
enumerateProviders();
}
+void CameraService::updateCameraNumAndIds() {
+ Mutex::Autolock l(mServiceLock);
+ mNumberOfCameras = mCameraProviderManager->getCameraCount();
+ mNormalDeviceIds =
+ mCameraProviderManager->getAPI1CompatibleCameraDeviceIds();
+}
+
void CameraService::addStates(const String8 id) {
std::string cameraId(id.c_str());
hardware::camera::common::V1_0::CameraResourceCost cost;
@@ -313,10 +244,13 @@
if (mFlashlight->hasFlashUnit(id)) {
mTorchStatusMap.add(id, TorchModeStatus::AVAILABLE_OFF);
}
+
+ updateCameraNumAndIds();
logDeviceAdded(id, "Device added");
}
void CameraService::removeStates(const String8 id) {
+ updateCameraNumAndIds();
if (mFlashlight->hasFlashUnit(id)) {
mTorchStatusMap.removeItem(id);
}
@@ -361,15 +295,16 @@
if (newStatus == StatusInternal::NOT_PRESENT) {
logDeviceRemoved(id, String8::format("Device status changed from %d to %d", oldStatus,
newStatus));
+
+ // Set the device status to NOT_PRESENT, clients will no longer be able to connect
+ // to this device until the status changes
+ updateStatus(StatusInternal::NOT_PRESENT, id);
+
sp<BasicClient> clientToDisconnect;
{
// Don't do this in updateStatus to avoid deadlock over mServiceLock
Mutex::Autolock lock(mServiceLock);
- // Set the device status to NOT_PRESENT, clients will no longer be able to connect
- // to this device until the status changes
- updateStatus(StatusInternal::NOT_PRESENT, id);
-
// Remove cached shim parameters
state->setShimParams(CameraParameters());
@@ -472,7 +407,7 @@
Mutex::Autolock l(mServiceLock);
switch (type) {
case CAMERA_TYPE_BACKWARD_COMPATIBLE:
- *numCameras = mNumberOfNormalCameras;
+ *numCameras = static_cast<int>(mNormalDeviceIds.size());
break;
case CAMERA_TYPE_ALL:
*numCameras = mNumberOfCameras;
@@ -502,7 +437,8 @@
}
Status ret = Status::ok();
- status_t err = mCameraProviderManager->getCameraInfo(std::to_string(cameraId), cameraInfo);
+ status_t err = mCameraProviderManager->getCameraInfo(
+ cameraIdIntToStrLocked(cameraId), cameraInfo);
if (err != OK) {
ret = STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
"Error retrieving camera info from device %d: %s (%d)", cameraId,
@@ -512,13 +448,19 @@
return ret;
}
-int CameraService::cameraIdToInt(const String8& cameraId) {
- int id;
- bool success = base::ParseInt(cameraId.string(), &id, 0);
- if (!success) {
- return -1;
+std::string CameraService::cameraIdIntToStrLocked(int cameraIdInt) {
+ if (cameraIdInt < 0 || cameraIdInt >= static_cast<int>(mNormalDeviceIds.size())) {
+ ALOGE("%s: input id %d invalid: valid range (0, %zu)",
+ __FUNCTION__, cameraIdInt, mNormalDeviceIds.size());
+ return std::string{};
}
- return id;
+
+ return mNormalDeviceIds[cameraIdInt];
+}
+
+String8 CameraService::cameraIdIntToStr(int cameraIdInt) {
+ Mutex::Autolock lock(mServiceLock);
+ return String8(cameraIdIntToStrLocked(cameraIdInt).c_str());
}
Status CameraService::getCameraCharacteristics(const String16& cameraId,
@@ -635,8 +577,8 @@
Status CameraService::makeClient(const sp<CameraService>& cameraService,
const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
- int facing, int clientPid, uid_t clientUid, int servicePid, bool legacyMode,
- int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
+ int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
+ bool legacyMode, int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
/*out*/sp<BasicClient>* client) {
if (halVersion < 0 || halVersion == deviceVersion) {
@@ -646,8 +588,9 @@
case CAMERA_DEVICE_API_VERSION_1_0:
if (effectiveApiLevel == API_1) { // Camera1 API route
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
- *client = new CameraClient(cameraService, tmp, packageName, cameraIdToInt(cameraId),
- facing, clientPid, clientUid, getpid(), legacyMode);
+ *client = new CameraClient(cameraService, tmp, packageName,
+ api1CameraId, facing, clientPid, clientUid,
+ getpid(), legacyMode);
} else { // Camera2 API route
ALOGW("Camera using old HAL version: %d", deviceVersion);
return STATUS_ERROR_FMT(ERROR_DEPRECATED_HAL,
@@ -662,8 +605,10 @@
case CAMERA_DEVICE_API_VERSION_3_4:
if (effectiveApiLevel == API_1) { // Camera1 API route
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
- *client = new Camera2Client(cameraService, tmp, packageName, cameraIdToInt(cameraId),
- facing, clientPid, clientUid, servicePid, legacyMode);
+ *client = new Camera2Client(cameraService, tmp, packageName,
+ cameraId, api1CameraId,
+ facing, clientPid, clientUid,
+ servicePid, legacyMode);
} else { // Camera2 API route
sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
@@ -685,8 +630,9 @@
halVersion == CAMERA_DEVICE_API_VERSION_1_0) {
// Only support higher HAL version device opened as HAL1.0 device.
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
- *client = new CameraClient(cameraService, tmp, packageName, cameraIdToInt(cameraId),
- facing, clientPid, clientUid, servicePid, legacyMode);
+ *client = new CameraClient(cameraService, tmp, packageName,
+ api1CameraId, facing, clientPid, clientUid,
+ servicePid, legacyMode);
} else {
// Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet.
ALOGE("Invalid camera HAL version %x: HAL %x device can only be"
@@ -782,7 +728,8 @@
Status ret = Status::ok();
sp<Client> tmp = nullptr;
if (!(ret = connectHelper<ICameraClient,Client>(
- sp<ICameraClient>{nullptr}, id, static_cast<int>(CAMERA_HAL_API_VERSION_UNSPECIFIED),
+ sp<ICameraClient>{nullptr}, id, cameraId,
+ static_cast<int>(CAMERA_HAL_API_VERSION_UNSPECIFIED),
internalPackageName, uid, USE_CALLING_PID,
API_1, /*legacyMode*/ false, /*shimUpdateOnly*/ true,
/*out*/ tmp)
@@ -1235,7 +1182,7 @@
Status CameraService::connect(
const sp<ICameraClient>& cameraClient,
- int cameraId,
+ int api1CameraId,
const String16& clientPackageName,
int clientUid,
int clientPid,
@@ -1244,9 +1191,10 @@
ATRACE_CALL();
Status ret = Status::ok();
- String8 id = String8::format("%d", cameraId);
+
+ String8 id = cameraIdIntToStr(api1CameraId);
sp<Client> client = nullptr;
- ret = connectHelper<ICameraClient,Client>(cameraClient, id,
+ ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId,
CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, clientPid, API_1,
/*legacyMode*/ false, /*shimUpdateOnly*/ false,
/*out*/client);
@@ -1263,18 +1211,18 @@
Status CameraService::connectLegacy(
const sp<ICameraClient>& cameraClient,
- int cameraId, int halVersion,
+ int api1CameraId, int halVersion,
const String16& clientPackageName,
int clientUid,
/*out*/
sp<ICamera>* device) {
ATRACE_CALL();
- String8 id = String8::format("%d", cameraId);
+ String8 id = cameraIdIntToStr(api1CameraId);
Status ret = Status::ok();
sp<Client> client = nullptr;
- ret = connectHelper<ICameraClient,Client>(cameraClient, id, halVersion,
+ ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId, halVersion,
clientPackageName, clientUid, USE_CALLING_PID, API_1,
/*legacyMode*/ true, /*shimUpdateOnly*/ false,
/*out*/client);
@@ -1302,6 +1250,7 @@
String8 id = String8(cameraId);
sp<CameraDeviceClient> client = nullptr;
ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
+ /*api1CameraId*/-1,
CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName,
clientUid, USE_CALLING_PID, API_2,
/*legacyMode*/ false, /*shimUpdateOnly*/ false,
@@ -1319,8 +1268,8 @@
template<class CALLBACK, class CLIENT>
Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
- int halVersion, const String16& clientPackageName, int clientUid, int clientPid,
- apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
+ int api1CameraId, int halVersion, const String16& clientPackageName, int clientUid,
+ int clientPid, apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
/*out*/sp<CLIENT>& device) {
binder::Status ret = binder::Status::ok();
@@ -1403,8 +1352,10 @@
}
sp<BasicClient> tmp = nullptr;
- if(!(ret = makeClient(this, cameraCb, clientPackageName, cameraId, facing, clientPid,
- clientUid, getpid(), legacyMode, halVersion, deviceVersion, effectiveApiLevel,
+ if(!(ret = makeClient(this, cameraCb, clientPackageName,
+ cameraId, api1CameraId, facing,
+ clientPid, clientUid, getpid(), legacyMode,
+ halVersion, deviceVersion, effectiveApiLevel,
/*out*/&tmp)).isOk()) {
return ret;
}
@@ -2112,7 +2063,8 @@
CameraService::Client::Client(const sp<CameraService>& cameraService,
const sp<ICameraClient>& cameraClient,
const String16& clientPackageName,
- const String8& cameraIdStr, int cameraFacing,
+ const String8& cameraIdStr,
+ int api1CameraId, int cameraFacing,
int clientPid, uid_t clientUid,
int servicePid) :
CameraService::BasicClient(cameraService,
@@ -2121,7 +2073,7 @@
cameraIdStr, cameraFacing,
clientPid, clientUid,
servicePid),
- mCameraId(CameraService::cameraIdToInt(cameraIdStr))
+ mCameraId(api1CameraId)
{
int callingPid = getCallingPid();
LOG1("Client::Client E (pid %d, id %d)", callingPid, mCameraId);
@@ -2676,7 +2628,10 @@
}
dprintf(fd, "\n== Service global info: ==\n\n");
dprintf(fd, "Number of camera devices: %d\n", mNumberOfCameras);
- dprintf(fd, "Number of normal camera devices: %d\n", mNumberOfNormalCameras);
+ dprintf(fd, "Number of normal camera devices: %zu\n", mNormalDeviceIds.size());
+ for (size_t i = 0; i < mNormalDeviceIds.size(); i++) {
+ dprintf(fd, " Device %zu maps to \"%s\"\n", i, mNormalDeviceIds[i].c_str());
+ }
String8 activeClientString = mActiveClientManager.toString();
dprintf(fd, "Active Camera Clients:\n%s", activeClientString.string());
dprintf(fd, "Allowed user IDs: %s\n", toString(mAllowedUsers).string());
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 67db7ec..81048e6 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -62,7 +62,6 @@
public BinderService<CameraService>,
public virtual ::android::hardware::BnCameraService,
public virtual IBinder::DeathRecipient,
- public camera_module_callbacks_t,
public virtual CameraProviderManager::StatusListener
{
friend class BinderService<CameraService>;
@@ -333,6 +332,7 @@
const sp<hardware::ICameraClient>& cameraClient,
const String16& clientPackageName,
const String8& cameraIdStr,
+ int api1CameraId,
int cameraFacing,
int clientPid,
uid_t clientUid,
@@ -551,7 +551,8 @@
// Eumerate all camera providers in the system
status_t enumerateProviders();
- // Add a new camera to camera and torch state lists or remove an unplugged one
+ // Add/remove a new camera to camera and torch state lists or remove an unplugged one
+ // Caller must not hold mServiceLock
void addStates(const String8 id);
void removeStates(const String8 id);
@@ -578,7 +579,7 @@
// Single implementation shared between the various connect calls
template<class CALLBACK, class CLIENT>
binder::Status connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
- int halVersion, const String16& clientPackageName,
+ int api1CameraId, int halVersion, const String16& clientPackageName,
int clientUid, int clientPid,
apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
/*out*/sp<CLIENT>& device);
@@ -640,9 +641,16 @@
void finishConnectLocked(const sp<BasicClient>& client, const DescriptorPtr& desc);
/**
- * Returns the integer corresponding to the given camera ID string, or -1 on failure.
+ * Returns the underlying camera Id string mapped to a camera id int
+ * Empty string is returned when the cameraIdInt is invalid.
*/
- static int cameraIdToInt(const String8& cameraId);
+ String8 cameraIdIntToStr(int cameraIdInt);
+
+ /**
+ * Returns the underlying camera Id string mapped to a camera id int
+ * Empty string is returned when the cameraIdInt is invalid.
+ */
+ std::string cameraIdIntToStrLocked(int cameraIdInt);
/**
* Remove a single client corresponding to the given camera id from the list of active clients.
@@ -710,8 +718,14 @@
*/
void dumpEventLog(int fd);
+ /**
+ * This method will acquire mServiceLock
+ */
+ void updateCameraNumAndIds();
+
int mNumberOfCameras;
- int mNumberOfNormalCameras;
+
+ std::vector<std::string> mNormalDeviceIds;
// sounds
MediaPlayer* newMediaPlayer(const char *file);
@@ -821,8 +835,8 @@
static binder::Status makeClient(const sp<CameraService>& cameraService,
const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
- int facing, int clientPid, uid_t clientUid, int servicePid, bool legacyMode,
- int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
+ int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
+ bool legacyMode, int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
/*out*/sp<BasicClient>* client);
status_t checkCameraAccess(const String16& opPackageName);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 585d2eb..0a82cb9 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -49,16 +49,17 @@
Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
const sp<hardware::ICameraClient>& cameraClient,
const String16& clientPackageName,
- int cameraId,
+ const String8& cameraDeviceId,
+ int api1CameraId,
int cameraFacing,
int clientPid,
uid_t clientUid,
int servicePid,
bool legacyMode):
Camera2ClientBase(cameraService, cameraClient, clientPackageName,
- String8::format("%d", cameraId), cameraFacing,
+ cameraDeviceId, api1CameraId, cameraFacing,
clientPid, clientUid, servicePid),
- mParameters(cameraId, cameraFacing)
+ mParameters(api1CameraId, cameraFacing)
{
ATRACE_CALL();
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 5af74eb..1ebf4b0 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -91,7 +91,8 @@
Camera2Client(const sp<CameraService>& cameraService,
const sp<hardware::ICameraClient>& cameraClient,
const String16& clientPackageName,
- int cameraId,
+ const String8& cameraDeviceId,
+ int api1CameraId,
int cameraFacing,
int clientPid,
uid_t clientUid,
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index e848a3f..8c6cd3d 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -42,7 +42,7 @@
int clientPid, int clientUid,
int servicePid, bool legacyMode):
Client(cameraService, cameraClient, clientPackageName,
- String8::format("%d", cameraId), cameraFacing, clientPid,
+ String8::format("%d", cameraId), cameraId, cameraFacing, clientPid,
clientUid, servicePid)
{
int callingPid = getCallingPid();
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 050c3f7..b4c7e9d 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -759,12 +759,17 @@
focusingAreas.clear();
focusingAreas.add(Parameters::Area(0,0,0,0,0));
- camera_metadata_ro_entry_t availableFocalLengths =
- staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, 0, 0, false);
- if (!availableFocalLengths.count) return NO_INIT;
+ if (fastInfo.isExternalCamera) {
+ params.setFloat(CameraParameters::KEY_FOCAL_LENGTH, -1.0);
+ } else {
+ camera_metadata_ro_entry_t availableFocalLengths =
+ staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, 0, 0, false);
+ if (!availableFocalLengths.count) return NO_INIT;
- float minFocalLength = availableFocalLengths.data.f[0];
- params.setFloat(CameraParameters::KEY_FOCAL_LENGTH, minFocalLength);
+ float minFocalLength = availableFocalLengths.data.f[0];
+ params.setFloat(CameraParameters::KEY_FOCAL_LENGTH, minFocalLength);
+ }
+
float horizFov, vertFov;
res = calculatePictureFovs(&horizFov, &vertFov);
@@ -1091,9 +1096,15 @@
focusDistanceCalibration.data.u8[0] !=
ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED);
+
+ camera_metadata_ro_entry_t hwLevel = staticInfo(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL);
+ if (!hwLevel.count) return NO_INIT;
+ fastInfo.isExternalCamera =
+ hwLevel.data.u8[0] == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL;
+
camera_metadata_ro_entry_t availableFocalLengths =
- staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
- if (!availableFocalLengths.count) return NO_INIT;
+ staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, 0, 0, /*required*/false);
+ if (!availableFocalLengths.count && !fastInfo.isExternalCamera) return NO_INIT;
SortedVector<int32_t> availableFormats = getAvailableOutputFormats();
if (!availableFormats.size()) return NO_INIT;
@@ -1178,10 +1189,14 @@
// Find smallest (widest-angle) focal length to use as basis of still
// picture FOV reporting.
- fastInfo.minFocalLength = availableFocalLengths.data.f[0];
- for (size_t i = 1; i < availableFocalLengths.count; i++) {
- if (fastInfo.minFocalLength > availableFocalLengths.data.f[i]) {
- fastInfo.minFocalLength = availableFocalLengths.data.f[i];
+ if (fastInfo.isExternalCamera) {
+ fastInfo.minFocalLength = -1.0;
+ } else {
+ fastInfo.minFocalLength = availableFocalLengths.data.f[0];
+ for (size_t i = 1; i < availableFocalLengths.count; i++) {
+ if (fastInfo.minFocalLength > availableFocalLengths.data.f[i]) {
+ fastInfo.minFocalLength = availableFocalLengths.data.f[i];
+ }
}
}
@@ -2870,8 +2885,13 @@
if (sc.isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
sc.format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
sc.width <= limit.width && sc.height <= limit.height) {
- Size sz = {sc.width, sc.height};
- sizes->push(sz);
+ int64_t minFrameDuration = getMinFrameDurationNs(
+ {sc.width, sc.height}, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
+ if (minFrameDuration > MAX_PREVIEW_RECORD_DURATION_NS) {
+ // Filter slow sizes from preview/record
+ continue;
+ }
+ sizes->push({sc.width, sc.height});
}
}
@@ -3081,6 +3101,16 @@
status_t Parameters::calculatePictureFovs(float *horizFov, float *vertFov)
const {
+ if (fastInfo.isExternalCamera) {
+ if (horizFov != NULL) {
+ *horizFov = -1.0;
+ }
+ if (vertFov != NULL) {
+ *vertFov = -1.0;
+ }
+ return OK;
+ }
+
camera_metadata_ro_entry_t sensorSize =
staticInfo(ANDROID_SENSOR_INFO_PHYSICAL_SIZE, 2, 2);
if (!sensorSize.count) return NO_INIT;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 17e3d75..fe725fd 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -207,6 +207,11 @@
static const int32_t FPS_MARGIN = 1;
// Max FPS for default parameters
static const int32_t MAX_DEFAULT_FPS = 30;
+ // Minimum FPS for a size to be listed in supported preview/video sizes
+ // Set to slightly less than 30.0 to have some tolerance margin
+ static constexpr double MIN_PREVIEW_RECORD_FPS = 29.97;
+ // Maximum frame duration for a size to be listed in supported preview/video sizes
+ static constexpr int64_t MAX_PREVIEW_RECORD_DURATION_NS = 1e9 / MIN_PREVIEW_RECORD_FPS;
// Full static camera info, object owned by someone else, such as
// Camera2Device.
@@ -233,6 +238,7 @@
}
};
DefaultKeyedVector<uint8_t, OverrideModes> sceneModeOverrides;
+ bool isExternalCamera;
float minFocalLength;
bool useFlexibleYuv;
Size maxJpegSize;
@@ -380,6 +386,7 @@
Vector<Size> availablePreviewSizes;
Vector<Size> availableVideoSizes;
// Get size list (that are no larger than limit) from static metadata.
+ // This method filtered size with minFrameDuration < MAX_PREVIEW_RECORD_DURATION_NS
status_t getFilteredSizes(Size limit, Vector<Size> *sizes);
// Get max size (from the size array) that matches the given aspect ratio.
Size getMaxSizeForRatio(float ratio, const int32_t* sizeArray, size_t count);
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 8e112a1..a7cc3c3 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -28,6 +28,8 @@
#include "common/CameraDeviceBase.h"
#include "api2/CameraDeviceClient.h"
+#include <camera_metadata_hidden.h>
+
// Convenience methods for constructing binder::Status objects for error returns
#define STATUS_ERROR(errorCode, errorString) \
@@ -47,6 +49,7 @@
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
const String16& clientPackageName,
const String8& cameraId,
+ int api1CameraId,
int cameraFacing,
int clientPid,
uid_t clientUid,
@@ -60,6 +63,8 @@
clientUid,
servicePid),
mRemoteCallback(remoteCallback) {
+ // We don't need it for API2 clients, but Camera2ClientBase requires it.
+ (void) api1CameraId;
}
// Interface used by CameraService
@@ -73,7 +78,8 @@
uid_t clientUid,
int servicePid) :
Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
- cameraId, cameraFacing, clientPid, clientUid, servicePid),
+ cameraId, /*API1 camera ID*/ -1,
+ cameraFacing, clientPid, clientUid, servicePid),
mInputStream(),
mStreamingRequestId(REQUEST_ID_NONE),
mRequestIdCounter(0) {
@@ -106,6 +112,15 @@
/*listener*/this,
/*sendPartials*/true);
+ auto deviceInfo = mDevice->info();
+ camera_metadata_entry_t physicalKeysEntry = deviceInfo.find(
+ ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS);
+ if (physicalKeysEntry.count > 0) {
+ mSupportedPhysicalRequestKeys.insert(mSupportedPhysicalRequestKeys.begin(),
+ physicalKeysEntry.data.i32,
+ physicalKeysEntry.data.i32 + physicalKeysEntry.count);
+ }
+
return OK;
}
@@ -291,6 +306,13 @@
CameraDeviceBase::PhysicalCameraSettingsList physicalSettingsList;
for (const auto& it : request.mPhysicalCameraSettings) {
+ if (it.settings.isEmpty()) {
+ ALOGE("%s: Camera %s: Sent empty metadata packet. Rejecting request.",
+ __FUNCTION__, mCameraIdStr.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "Request settings are empty");
+ }
+
String8 physicalId(it.id.c_str());
if (physicalId != mDevice->getId()) {
auto found = std::find(requestedPhysicalIds.begin(), requestedPhysicalIds.end(),
@@ -301,24 +323,27 @@
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
"Invalid physical camera id");
}
+
+ if (!mSupportedPhysicalRequestKeys.empty()) {
+ // Filter out any unsupported physical request keys.
+ CameraMetadata filteredParams(mSupportedPhysicalRequestKeys.size());
+ camera_metadata_t *meta = const_cast<camera_metadata_t *>(
+ filteredParams.getAndLock());
+ set_camera_metadata_vendor_id(meta, mDevice->getVendorTagId());
+ filteredParams.unlock(meta);
+
+ for (const auto& keyIt : mSupportedPhysicalRequestKeys) {
+ camera_metadata_ro_entry entry = it.settings.find(keyIt);
+ if (entry.count > 0) {
+ filteredParams.update(entry);
+ }
+ }
+
+ physicalSettingsList.push_back({it.id, filteredParams});
+ }
+ } else {
+ physicalSettingsList.push_back({it.id, it.settings});
}
-
- CameraMetadata metadata(it.settings);
- if (metadata.isEmpty()) {
- ALOGE("%s: Camera %s: Sent empty metadata packet. Rejecting request.",
- __FUNCTION__, mCameraIdStr.string());
- return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
- "Request settings are empty");
- }
-
- physicalSettingsList.push_back({it.id, metadata});
- }
-
- if (streaming && (physicalSettingsList.size() > 1)) {
- ALOGE("%s: Camera %s: Individual physical camera settings are not supported in "
- "streaming requests. Rejecting request.", __FUNCTION__, mCameraIdStr.string());
- return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
- "Streaming request contains individual physical requests");
}
if (!enforceRequestPermissions(physicalSettingsList.begin()->metadata)) {
@@ -633,14 +658,6 @@
return res;
if (!isStreamInfoValid) {
- // Streaming sharing is only supported for IMPLEMENTATION_DEFINED
- // formats.
- if (isShared && streamInfo.format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
- String8 msg = String8::format("Camera %s: Stream sharing is only supported for "
- "IMPLEMENTATION_DEFINED format", mCameraIdStr.string());
- ALOGW("%s: %s", __FUNCTION__, msg.string());
- return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
- }
isStreamInfoValid = true;
}
@@ -920,14 +937,6 @@
if (!res.isOk())
return res;
- // Stream sharing is only supported for IMPLEMENTATION_DEFINED
- // formats.
- if (outInfo.format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
- String8 msg = String8::format("Camera %s: Stream sharing is only supported for "
- "IMPLEMENTATION_DEFINED format", mCameraIdStr.string());
- ALOGW("%s: %s", __FUNCTION__, msg.string());
- return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
- }
streamInfos.push_back(outInfo);
newOutputs.push_back(surface);
}
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 435c99d..4e049d8 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -45,6 +45,7 @@
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
const String16& clientPackageName,
const String8& cameraId,
+ int api1CameraId,
int cameraFacing,
int clientPid,
uid_t clientUid,
@@ -221,6 +222,8 @@
static const int32_t FRAME_PROCESSOR_LISTENER_MIN_ID = 0;
static const int32_t FRAME_PROCESSOR_LISTENER_MAX_ID = 0x7fffffffL;
+ std::vector<int32_t> mSupportedPhysicalRequestKeys;
+
template<typename TProviderPtr>
status_t initializeImpl(TProviderPtr providerPtr);
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 4ce82dc..db26027 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -48,15 +48,16 @@
const sp<TCamCallbacks>& remoteCallback,
const String16& clientPackageName,
const String8& cameraId,
+ int api1CameraId,
int cameraFacing,
int clientPid,
uid_t clientUid,
int servicePid):
TClientBase(cameraService, remoteCallback, clientPackageName,
- cameraId, cameraFacing, clientPid, clientUid, servicePid),
+ cameraId, api1CameraId, cameraFacing, clientPid, clientUid, servicePid),
mSharedCameraCallbacks(remoteCallback),
mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
- mDeviceActive(false)
+ mDeviceActive(false), mApi1CameraId(api1CameraId)
{
ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(),
String8(clientPackageName).string(), clientPid, clientUid);
@@ -329,7 +330,7 @@
template <typename TClientBase>
int Camera2ClientBase<TClientBase>::getCameraId() const {
- return std::stoi(TClientBase::mCameraIdStr.string());
+ return mApi1CameraId;
}
template <typename TClientBase>
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index e898d5d..edeae5b 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -49,6 +49,7 @@
const sp<TCamCallbacks>& remoteCallback,
const String16& clientPackageName,
const String8& cameraId,
+ int api1CameraId,
int cameraFacing,
int clientPid,
uid_t clientUid,
@@ -140,6 +141,8 @@
bool mDeviceActive;
+ const int mApi1CameraId; // -1 if client is API2
+
private:
template<typename TProviderPtr>
status_t initializeImpl(TProviderPtr providerPtr);
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 7956be5..ad83c3d 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -55,6 +55,11 @@
*/
virtual const String8& getId() const = 0;
+ /**
+ * The device vendor tag ID
+ */
+ virtual metadata_vendor_id_t getVendorTagId() const = 0;
+
virtual status_t initialize(sp<CameraProviderManager> manager) = 0;
virtual status_t disconnect() = 0;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 70e7761..b37f004 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -20,11 +20,13 @@
#include "CameraProviderManager.h"
+#include <algorithm>
#include <chrono>
#include <inttypes.h>
#include <hidl/ServiceManagement.h>
#include <functional>
#include <camera_metadata_hidden.h>
+#include <android-base/parseint.h>
namespace android {
@@ -38,7 +40,7 @@
const std::string kExternalProviderName("external/0");
// Slash-separated list of provider types to consider for use via the old camera API
-const std::string kStandardProviderTypes("internal/legacy");
+const std::string kStandardProviderTypes("internal/legacy/external");
} // anonymous namespace
@@ -79,18 +81,7 @@
std::lock_guard<std::mutex> lock(mInterfaceMutex);
int count = 0;
for (auto& provider : mProviders) {
- count += provider->mUniqueDeviceCount;
- }
- return count;
-}
-
-int CameraProviderManager::getAPI1CompatibleCameraCount() const {
- std::lock_guard<std::mutex> lock(mInterfaceMutex);
- int count = 0;
- for (auto& provider : mProviders) {
- if (kStandardProviderTypes.find(provider->getType()) != std::string::npos) {
- count += provider->mUniqueAPI1CompatibleCameraIds.size();
- }
+ count += provider->mUniqueCameraIds.size();
}
return count;
}
@@ -116,6 +107,24 @@
}
}
}
+
+ std::sort(deviceIds.begin(), deviceIds.end(),
+ [](const std::string& a, const std::string& b) -> bool {
+ uint32_t aUint = 0, bUint = 0;
+ bool aIsUint = base::ParseUint(a, &aUint);
+ bool bIsUint = base::ParseUint(b, &bUint);
+
+ // Uint device IDs first
+ if (aIsUint && bIsUint) {
+ return aUint < bUint;
+ } else if (aIsUint) {
+ return true;
+ } else if (bIsUint) {
+ return false;
+ }
+ // Simple string compare if both id are not uint
+ return a < b;
+ });
return deviceIds;
}
@@ -480,6 +489,8 @@
}
ALOGI("Connecting to new camera provider: %s, isRemote? %d",
mProviderName.c_str(), mInterface->isRemote());
+ // cameraDeviceStatusChange callbacks may be called (and causing new devices added)
+ // before setCallback returns
hardware::Return<Status> status = mInterface->setCallback(this);
if (!status.isOk()) {
ALOGE("%s: Transaction error setting up callbacks with camera provider '%s': %s",
@@ -536,17 +547,10 @@
}
}
- for (auto& device : mDevices) {
- mUniqueCameraIds.insert(device->mId);
- if (device->isAPI1Compatible()) {
- mUniqueAPI1CompatibleCameraIds.insert(device->mId);
- }
- }
- mUniqueDeviceCount = mUniqueCameraIds.size();
-
ALOGI("Camera provider %s ready with %zu camera devices",
mProviderName.c_str(), mDevices.size());
+ mInitialized = true;
return OK;
}
@@ -594,9 +598,15 @@
}
if (deviceInfo == nullptr) return BAD_VALUE;
deviceInfo->mStatus = initialStatus;
+ bool isAPI1Compatible = deviceInfo->isAPI1Compatible();
mDevices.push_back(std::move(deviceInfo));
+ mUniqueCameraIds.insert(id);
+ if (isAPI1Compatible) {
+ mUniqueAPI1CompatibleCameraIds.insert(id);
+ }
+
if (parsedId != nullptr) {
*parsedId = id;
}
@@ -606,6 +616,10 @@
void CameraProviderManager::ProviderInfo::removeDevice(std::string id) {
for (auto it = mDevices.begin(); it != mDevices.end(); it++) {
if ((*it)->mId == id) {
+ mUniqueCameraIds.erase(id);
+ if ((*it)->isAPI1Compatible()) {
+ mUniqueAPI1CompatibleCameraIds.erase(id);
+ }
mDevices.erase(it);
break;
}
@@ -671,6 +685,7 @@
CameraDeviceStatus newStatus) {
sp<StatusListener> listener;
std::string id;
+ bool initialized = false;
{
std::lock_guard<std::mutex> lock(mLock);
bool known = false;
@@ -697,9 +712,13 @@
removeDevice(id);
}
listener = mManager->getStatusListener();
+ initialized = mInitialized;
}
// Call without lock held to allow reentrancy into provider manager
- if (listener != nullptr) {
+ // Don't send the callback if providerInfo hasn't been initialized.
+ // CameraService will initialize device status after provider is
+ // initialized
+ if (listener != nullptr && initialized) {
listener->onDeviceStatusChanged(String8(id.c_str()), newStatus);
}
return hardware::Void();
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index d02abb0..bbe6789 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -18,7 +18,7 @@
#define ANDROID_SERVERS_CAMERA_CAMERAPROVIDER_H
#include <vector>
-#include <set>
+#include <unordered_set>
#include <string>
#include <mutex>
@@ -125,16 +125,14 @@
*/
int getCameraCount() const;
+ std::vector<std::string> getCameraDeviceIds() const;
+
/**
* Retrieve the number of API1 compatible cameras; these are internal and
* backwards-compatible. This is the set of cameras that will be
- * accessible via the old camera API, with IDs in range of
- * [0, getAPI1CompatibleCameraCount()-1]. This value is not expected to change dynamically.
+ * accessible via the old camera API.
+ * The return value may change dynamically due to external camera hotplug.
*/
- int getAPI1CompatibleCameraCount() const;
-
- std::vector<std::string> getCameraDeviceIds() const;
-
std::vector<std::string> getAPI1CompatibleCameraDeviceIds() const;
/**
@@ -314,9 +312,9 @@
static status_t setTorchMode(InterfaceT& interface, bool enabled);
};
std::vector<std::unique_ptr<DeviceInfo>> mDevices;
- std::set<std::string> mUniqueCameraIds;
+ std::unordered_set<std::string> mUniqueCameraIds;
int mUniqueDeviceCount;
- std::set<std::string> mUniqueAPI1CompatibleCameraIds;
+ std::unordered_set<std::string> mUniqueAPI1CompatibleCameraIds;
// HALv1-specific camera fields, including the actual device interface
struct DeviceInfo1 : public DeviceInfo {
@@ -366,6 +364,8 @@
CameraProviderManager *mManager;
+ bool mInitialized = false;
+
// Templated method to instantiate the right kind of DeviceInfo and call the
// right CameraProvider getCameraDeviceInterface_* method.
template<class DeviceInfoT>
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 59bb2e2..04c2c5b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -3828,21 +3828,27 @@
if (hidlSession_3_4 != nullptr) {
captureRequests_3_4[i].physicalCameraSettings.resize(request->num_physcam_settings);
for (size_t j = 0; j < request->num_physcam_settings; j++) {
- size_t settingsSize = get_camera_metadata_size(request->physcam_settings[j]);
- if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write(
- reinterpret_cast<const uint8_t*>(request->physcam_settings[j]),
- settingsSize)) {
- captureRequests_3_4[i].physicalCameraSettings[j].settings.resize(0);
- captureRequests_3_4[i].physicalCameraSettings[j].fmqSettingsSize = settingsSize;
- } else {
- if (mRequestMetadataQueue != nullptr) {
- ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
+ if (request->physcam_settings != nullptr) {
+ size_t settingsSize = get_camera_metadata_size(request->physcam_settings[j]);
+ if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write(
+ reinterpret_cast<const uint8_t*>(request->physcam_settings[j]),
+ settingsSize)) {
+ captureRequests_3_4[i].physicalCameraSettings[j].settings.resize(0);
+ captureRequests_3_4[i].physicalCameraSettings[j].fmqSettingsSize =
+ settingsSize;
+ } else {
+ if (mRequestMetadataQueue != nullptr) {
+ ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
+ }
+ captureRequests_3_4[i].physicalCameraSettings[j].settings.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(
+ request->physcam_settings[j])),
+ get_camera_metadata_size(request->physcam_settings[j]));
+ captureRequests_3_4[i].physicalCameraSettings[j].fmqSettingsSize = 0u;
}
- captureRequests_3_4[i].physicalCameraSettings[j].settings.setToExternal(
- reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(
- request->physcam_settings[j])),
- get_camera_metadata_size(request->physcam_settings[j]));
+ } else {
captureRequests_3_4[i].physicalCameraSettings[j].fmqSettingsSize = 0u;
+ captureRequests_3_4[i].physicalCameraSettings[j].settings.resize(0);
}
captureRequests_3_4[i].physicalCameraSettings[j].physicalCameraId =
request->physcam_id[j];
@@ -4680,7 +4686,8 @@
mPrevTriggers = triggerCount;
// If the request is the same as last, or we had triggers last time
- if (mPrevRequest != captureRequest || triggersMixedIn) {
+ bool newRequest = mPrevRequest != captureRequest || triggersMixedIn;
+ if (newRequest) {
/**
* HAL workaround:
* Insert a dummy trigger ID if a trigger is set but no trigger ID is
@@ -4725,14 +4732,20 @@
if (captureRequest->mSettingsList.size() > 1) {
halRequest->num_physcam_settings = captureRequest->mSettingsList.size() - 1;
halRequest->physcam_id = new const char* [halRequest->num_physcam_settings];
- halRequest->physcam_settings =
- new const camera_metadata* [halRequest->num_physcam_settings];
+ if (newRequest) {
+ halRequest->physcam_settings =
+ new const camera_metadata* [halRequest->num_physcam_settings];
+ } else {
+ halRequest->physcam_settings = nullptr;
+ }
auto it = ++captureRequest->mSettingsList.begin();
size_t i = 0;
for (; it != captureRequest->mSettingsList.end(); it++, i++) {
halRequest->physcam_id[i] = it->cameraId.c_str();
- it->metadata.sort();
- halRequest->physcam_settings[i] = it->metadata.getAndLock();
+ if (newRequest) {
+ it->metadata.sort();
+ halRequest->physcam_settings[i] = it->metadata.getAndLock();
+ }
}
}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 12cb6b4..7faa6e5 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -93,6 +93,8 @@
const String8& getId() const override;
+ metadata_vendor_id_t getVendorTagId() const override { return mVendorTagId; }
+
// Transitions to idle state on success.
status_t initialize(sp<CameraProviderManager> manager) override;
status_t disconnect() override;