summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/libmedia/IDrm.cpp60
-rw-r--r--media/libmediaplayerservice/Drm.cpp46
-rw-r--r--media/libmediaplayerservice/Drm.h14
-rw-r--r--media/libstagefright/ACodec.cpp121
-rw-r--r--media/libstagefright/MediaDefs.cpp1
-rw-r--r--media/libstagefright/OMXCodec.cpp93
-rw-r--r--media/libstagefright/mpeg2ts/ATSParser.cpp6
-rw-r--r--media/libstagefright/mpeg2ts/ATSParser.h4
-rw-r--r--media/libstagefright/mpeg2ts/ESQueue.cpp190
-rw-r--r--media/libstagefright/mpeg2ts/ESQueue.h2
10 files changed, 468 insertions, 69 deletions
diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp
index f7a9a75..f1a6a9f 100644
--- a/media/libmedia/IDrm.cpp
+++ b/media/libmedia/IDrm.cpp
@@ -51,6 +51,7 @@ enum {
ENCRYPT,
DECRYPT,
SIGN,
+ SIGN_RSA,
VERIFY,
SET_LISTENER
};
@@ -196,11 +197,15 @@ struct BpDrm : public BpInterface<IDrm> {
return reply.readInt32();
}
- virtual status_t getProvisionRequest(Vector<uint8_t> &request,
+ virtual status_t getProvisionRequest(String8 const &certType,
+ String8 const &certAuthority,
+ Vector<uint8_t> &request,
String8 &defaultUrl) {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+ data.writeString8(certType);
+ data.writeString8(certAuthority);
remote()->transact(GET_PROVISION_REQUEST, data, &reply);
readVector(reply, request);
@@ -209,13 +214,18 @@ struct BpDrm : public BpInterface<IDrm> {
return reply.readInt32();
}
- virtual status_t provideProvisionResponse(Vector<uint8_t> const &response) {
+ virtual status_t provideProvisionResponse(Vector<uint8_t> const &response,
+ Vector<uint8_t> &certificate,
+ Vector<uint8_t> &wrappedKey) {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
writeVector(data, response);
remote()->transact(PROVIDE_PROVISION_RESPONSE, data, &reply);
+ readVector(reply, certificate);
+ readVector(reply, wrappedKey);
+
return reply.readInt32();
}
@@ -386,6 +396,25 @@ struct BpDrm : public BpInterface<IDrm> {
return reply.readInt32();
}
+ virtual status_t signRSA(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> const &wrappedKey,
+ Vector<uint8_t> &signature) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+ writeVector(data, sessionId);
+ data.writeString8(algorithm);
+ writeVector(data, message);
+ writeVector(data, wrappedKey);
+
+ remote()->transact(SIGN_RSA, data, &reply);
+ readVector(reply, signature);
+
+ return reply.readInt32();
+ }
+
virtual status_t setListener(const sp<IDrmClient>& listener) {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
@@ -563,9 +592,13 @@ status_t BnDrm::onTransact(
case GET_PROVISION_REQUEST:
{
CHECK_INTERFACE(IDrm, data, reply);
+ String8 certType = data.readString8();
+ String8 certAuthority = data.readString8();
+
Vector<uint8_t> request;
String8 defaultUrl;
- status_t result = getProvisionRequest(request, defaultUrl);
+ status_t result = getProvisionRequest(certType, certAuthority,
+ request, defaultUrl);
writeVector(reply, request);
reply->writeString8(defaultUrl);
reply->writeInt32(result);
@@ -576,8 +609,13 @@ status_t BnDrm::onTransact(
{
CHECK_INTERFACE(IDrm, data, reply);
Vector<uint8_t> response;
+ Vector<uint8_t> certificate;
+ Vector<uint8_t> wrappedKey;
readVector(data, response);
- reply->writeInt32(provideProvisionResponse(response));
+ status_t result = provideProvisionResponse(response, certificate, wrappedKey);
+ writeVector(reply, certificate);
+ writeVector(reply, wrappedKey);
+ reply->writeInt32(result);
return OK;
}
@@ -725,6 +763,20 @@ status_t BnDrm::onTransact(
return OK;
}
+ case SIGN_RSA:
+ {
+ CHECK_INTERFACE(IDrm, data, reply);
+ Vector<uint8_t> sessionId, message, wrappedKey, signature;
+ readVector(data, sessionId);
+ String8 algorithm = data.readString8();
+ readVector(data, message);
+ readVector(data, wrappedKey);
+ uint32_t result = signRSA(sessionId, algorithm, message, wrappedKey, signature);
+ writeVector(reply, signature);
+ reply->writeInt32(result);
+ return OK;
+ }
+
case SET_LISTENER: {
CHECK_INTERFACE(IDrm, data, reply);
sp<IDrmClient> listener =
diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp
index eebcb79..d50037f 100644
--- a/media/libmediaplayerservice/Drm.cpp
+++ b/media/libmediaplayerservice/Drm.cpp
@@ -28,9 +28,21 @@
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaErrors.h>
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
namespace android {
+static bool checkPermission(const char* permissionString) {
+#ifndef HAVE_ANDROID_OS
+ return true;
+#endif
+ if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
+ bool ok = checkCallingPermission(String16(permissionString));
+ if (!ok) ALOGE("Request requires %s", permissionString);
+ return ok;
+}
+
KeyedVector<Vector<uint8_t>, String8> Drm::mUUIDToLibraryPathMap;
KeyedVector<String8, wp<SharedLibrary> > Drm::mLibraryPathToOpenLibraryMap;
Mutex Drm::mMapLock;
@@ -373,7 +385,8 @@ status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId,
return mPlugin->queryKeyStatus(sessionId, infoMap);
}
-status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) {
+status_t Drm::getProvisionRequest(String8 const &certType, String8 const &certAuthority,
+ Vector<uint8_t> &request, String8 &defaultUrl) {
Mutex::Autolock autoLock(mLock);
if (mInitCheck != OK) {
@@ -384,10 +397,13 @@ status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl)
return -EINVAL;
}
- return mPlugin->getProvisionRequest(request, defaultUrl);
+ return mPlugin->getProvisionRequest(certType, certAuthority,
+ request, defaultUrl);
}
-status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) {
+status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response,
+ Vector<uint8_t> &certificate,
+ Vector<uint8_t> &wrappedKey) {
Mutex::Autolock autoLock(mLock);
if (mInitCheck != OK) {
@@ -398,7 +414,7 @@ status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) {
return -EINVAL;
}
- return mPlugin->provideProvisionResponse(response);
+ return mPlugin->provideProvisionResponse(response, certificate, wrappedKey);
}
@@ -589,6 +605,28 @@ status_t Drm::verify(Vector<uint8_t> const &sessionId,
return mPlugin->verify(sessionId, keyId, message, signature, match);
}
+status_t Drm::signRSA(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> const &wrappedKey,
+ Vector<uint8_t> &signature) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPlugin == NULL) {
+ return -EINVAL;
+ }
+
+ if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) {
+ return -EPERM;
+ }
+
+ return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature);
+}
+
void Drm::binderDied(const wp<IBinder> &the_late_who)
{
delete mPlugin;
diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h
index 119fd50..3d4b0fc 100644
--- a/media/libmediaplayerservice/Drm.h
+++ b/media/libmediaplayerservice/Drm.h
@@ -66,10 +66,14 @@ struct Drm : public BnDrm,
virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
KeyedVector<String8, String8> &infoMap) const;
- virtual status_t getProvisionRequest(Vector<uint8_t> &request,
+ virtual status_t getProvisionRequest(String8 const &certType,
+ String8 const &certAuthority,
+ Vector<uint8_t> &request,
String8 &defaulUrl);
- virtual status_t provideProvisionResponse(Vector<uint8_t> const &response);
+ virtual status_t provideProvisionResponse(Vector<uint8_t> const &response,
+ Vector<uint8_t> &certificate,
+ Vector<uint8_t> &wrappedKey);
virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops);
@@ -111,6 +115,12 @@ struct Drm : public BnDrm,
Vector<uint8_t> const &signature,
bool &match);
+ virtual status_t signRSA(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> const &wrappedKey,
+ Vector<uint8_t> &signature);
+
virtual status_t setListener(const sp<IDrmClient>& listener);
virtual void sendEvent(DrmPlugin::EventType eventType, int extra,
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index f5fb622..08a3c7f 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -37,7 +37,9 @@
#include <media/hardware/HardwareAPI.h>
+#include <OMX_AudioExt.h>
#include <OMX_Component.h>
+#include <OMX_IndexExt.h>
#include "include/avc_utils.h"
@@ -640,34 +642,18 @@ status_t ACodec::configureOutputBuffersFromNativeWindow(
return err;
}
- // FIXME: assume that surface is controlled by app (native window
- // returns the number for the case when surface is not controlled by app)
- // FIXME2: This means that minUndeqeueudBufs can be 1 larger than reported
- // For now, try to allocate 1 more buffer, but don't fail if unsuccessful
-
- // Use conservative allocation while also trying to reduce starvation
- //
- // 1. allocate at least nBufferCountMin + minUndequeuedBuffers - that is the
- // minimum needed for the consumer to be able to work
- // 2. try to allocate two (2) additional buffers to reduce starvation from
- // the consumer
- // plus an extra buffer to account for incorrect minUndequeuedBufs
- for (OMX_U32 extraBuffers = 2 + 1; /* condition inside loop */; extraBuffers--) {
- OMX_U32 newBufferCount =
- def.nBufferCountMin + *minUndequeuedBuffers + extraBuffers;
+ // XXX: Is this the right logic to use? It's not clear to me what the OMX
+ // buffer counts refer to - how do they account for the renderer holding on
+ // to buffers?
+ if (def.nBufferCountActual < def.nBufferCountMin + *minUndequeuedBuffers) {
+ OMX_U32 newBufferCount = def.nBufferCountMin + *minUndequeuedBuffers;
def.nBufferCountActual = newBufferCount;
err = mOMX->setParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- if (err == OK) {
- *minUndequeuedBuffers += extraBuffers;
- break;
- }
-
- ALOGW("[%s] setting nBufferCountActual to %lu failed: %d",
- mComponentName.c_str(), newBufferCount, err);
- /* exit condition */
- if (extraBuffers == 0) {
+ if (err != OK) {
+ ALOGE("[%s] setting nBufferCountActual to %lu failed: %d",
+ mComponentName.c_str(), newBufferCount, err);
return err;
}
}
@@ -692,7 +678,6 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() {
&bufferCount, &bufferSize, &minUndequeuedBuffers);
if (err != 0)
return err;
- mNumUndequeuedBuffers = minUndequeuedBuffers;
ALOGV("[%s] Allocating %lu buffers from a native window of size %lu on "
"output port",
@@ -758,7 +743,6 @@ status_t ACodec::allocateOutputMetaDataBuffers() {
&bufferCount, &bufferSize, &minUndequeuedBuffers);
if (err != 0)
return err;
- mNumUndequeuedBuffers = minUndequeuedBuffers;
ALOGV("[%s] Allocating %lu meta buffers on output port",
mComponentName.c_str(), bufferCount);
@@ -999,6 +983,10 @@ status_t ACodec::setComponentRole(
"audio_decoder.flac", "audio_encoder.flac" },
{ MEDIA_MIMETYPE_AUDIO_MSGSM,
"audio_decoder.gsm", "audio_encoder.gsm" },
+ { MEDIA_MIMETYPE_VIDEO_MPEG2,
+ "video_decoder.mpeg2", "video_encoder.mpeg2" },
+ { MEDIA_MIMETYPE_AUDIO_AC3,
+ "audio_decoder.ac3", "audio_encoder.ac3" },
};
static const size_t kNumMimeToRole =
@@ -1297,6 +1285,15 @@ status_t ACodec::configureCodec(
} else {
err = setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
}
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC3)) {
+ int32_t numChannels;
+ int32_t sampleRate;
+ if (!msg->findInt32("channel-count", &numChannels)
+ || !msg->findInt32("sample-rate", &sampleRate)) {
+ err = INVALID_OPERATION;
+ } else {
+ err = setupAC3Codec(encoder, numChannels, sampleRate);
+ }
}
if (err != OK) {
@@ -1493,6 +1490,44 @@ status_t ACodec::setupAACCodec(
mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
}
+status_t ACodec::setupAC3Codec(
+ bool encoder, int32_t numChannels, int32_t sampleRate) {
+ status_t err = setupRawAudioFormat(
+ encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels);
+
+ if (err != OK) {
+ return err;
+ }
+
+ if (encoder) {
+ ALOGW("AC3 encoding is not supported.");
+ return INVALID_OPERATION;
+ }
+
+ OMX_AUDIO_PARAM_ANDROID_AC3TYPE def;
+ InitOMXParams(&def);
+ def.nPortIndex = kPortIndexInput;
+
+ err = mOMX->getParameter(
+ mNode,
+ (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3,
+ &def,
+ sizeof(def));
+
+ if (err != OK) {
+ return err;
+ }
+
+ def.nChannels = numChannels;
+ def.nSampleRate = sampleRate;
+
+ return mOMX->setParameter(
+ mNode,
+ (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3,
+ &def,
+ sizeof(def));
+}
+
static OMX_AUDIO_AMRBANDMODETYPE pickModeFromBitRate(
bool isAMRWB, int32_t bps) {
if (isAMRWB) {
@@ -2449,7 +2484,19 @@ void ACodec::waitUntilAllPossibleNativeWindowBuffersAreReturnedToUs() {
return;
}
- while (countBuffersOwnedByNativeWindow() > mNumUndequeuedBuffers
+ int minUndequeuedBufs = 0;
+ status_t err = mNativeWindow->query(
+ mNativeWindow.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &minUndequeuedBufs);
+
+ if (err != OK) {
+ ALOGE("[%s] NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d)",
+ mComponentName.c_str(), strerror(-err), -err);
+
+ minUndequeuedBufs = 0;
+ }
+
+ while (countBuffersOwnedByNativeWindow() > (size_t)minUndequeuedBufs
&& dequeueBufferFromNativeWindow() != NULL) {
// these buffers will be submitted as regular buffers; account for this
if (mStoreMetaDataInOutputBuffers && mMetaDataBuffersToSubmit > 0) {
@@ -2575,7 +2622,7 @@ void ACodec::sendFormatChange(const sp<AMessage> &reply) {
{
OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio;
- switch (audioDef->eEncoding) {
+ switch ((int)audioDef->eEncoding) {
case OMX_AUDIO_CodingPCM:
{
OMX_AUDIO_PARAM_PCMMODETYPE params;
@@ -2681,6 +2728,24 @@ void ACodec::sendFormatChange(const sp<AMessage> &reply) {
break;
}
+ case OMX_AUDIO_CodingAndroidAC3:
+ {
+ OMX_AUDIO_PARAM_ANDROID_AC3TYPE params;
+ InitOMXParams(&params);
+ params.nPortIndex = kPortIndexOutput;
+
+ CHECK_EQ((status_t)OK, mOMX->getParameter(
+ mNode,
+ (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3,
+ &params,
+ sizeof(params)));
+
+ notify->setString("mime", MEDIA_MIMETYPE_AUDIO_AC3);
+ notify->setInt32("channel-count", params.nChannels);
+ notify->setInt32("sample-rate", params.nSampleRate);
+ break;
+ }
+
default:
TRESPASS();
}
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index b5d4e44..340cba7 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -42,6 +42,7 @@ const char *MEDIA_MIMETYPE_AUDIO_RAW = "audio/raw";
const char *MEDIA_MIMETYPE_AUDIO_FLAC = "audio/flac";
const char *MEDIA_MIMETYPE_AUDIO_AAC_ADTS = "audio/aac-adts";
const char *MEDIA_MIMETYPE_AUDIO_MSGSM = "audio/gsm";
+const char *MEDIA_MIMETYPE_AUDIO_AC3 = "audio/ac3";
const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mp4";
const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/x-wav";
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 450fb3b..96c5a32 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -42,7 +42,9 @@
#include <utils/Vector.h>
#include <OMX_Audio.h>
+#include <OMX_AudioExt.h>
#include <OMX_Component.h>
+#include <OMX_IndexExt.h>
#include "include/avc_utils.h"
@@ -94,7 +96,6 @@ static sp<MediaSource> InstantiateSoftwareEncoder(
#define CODEC_LOGI(x, ...) ALOGI("[%s] "x, mComponentName, ##__VA_ARGS__)
#define CODEC_LOGV(x, ...) ALOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
-#define CODEC_LOGW(x, ...) ALOGW("[%s] "x, mComponentName, ##__VA_ARGS__)
#define CODEC_LOGE(x, ...) ALOGE("[%s] "x, mComponentName, ##__VA_ARGS__)
struct OMXCodecObserver : public BnOMXObserver {
@@ -531,6 +532,17 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta) {
sampleRate,
numChannels);
}
+ } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AC3, mMIME)) {
+ int32_t numChannels;
+ int32_t sampleRate;
+ CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
+ CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+
+ status_t err = setAC3Format(numChannels, sampleRate);
+ if (err != OK) {
+ CODEC_LOGE("setAC3Format() failed (err = %d)", err);
+ return err;
+ }
} else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_ALAW, mMIME)
|| !strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_MLAW, mMIME)) {
// These are PCM-like formats with a fixed sample rate but
@@ -1397,6 +1409,10 @@ void OMXCodec::setComponentRole(
"audio_decoder.flac", "audio_encoder.flac" },
{ MEDIA_MIMETYPE_AUDIO_MSGSM,
"audio_decoder.gsm", "audio_encoder.gsm" },
+ { MEDIA_MIMETYPE_VIDEO_MPEG2,
+ "video_decoder.mpeg2", "video_encoder.mpeg2" },
+ { MEDIA_MIMETYPE_AUDIO_AC3,
+ "audio_decoder.ac3", "audio_encoder.ac3" },
};
static const size_t kNumMimeToRole =
@@ -1780,42 +1796,21 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() {
strerror(-err), -err);
return err;
}
- // FIXME: assume that surface is controlled by app (native window
- // returns the number for the case when surface is not controlled by app)
- // FIXME2: This means that minUndeqeueudBufs can be 1 larger than reported
- // For now, try to allocate 1 more buffer, but don't fail if unsuccessful
-
- // Use conservative allocation while also trying to reduce starvation
- //
- // 1. allocate at least nBufferCountMin + minUndequeuedBuffers - that is the
- // minimum needed for the consumer to be able to work
- // 2. try to allocate two (2) additional buffers to reduce starvation from
- // the consumer
- // plus an extra buffer to account for incorrect minUndequeuedBufs
- CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d+1",
- def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs);
-
- for (OMX_U32 extraBuffers = 2 + 1; /* condition inside loop */; extraBuffers--) {
- OMX_U32 newBufferCount =
- def.nBufferCountMin + minUndequeuedBufs + extraBuffers;
+
+ // XXX: Is this the right logic to use? It's not clear to me what the OMX
+ // buffer counts refer to - how do they account for the renderer holding on
+ // to buffers?
+ if (def.nBufferCountActual < def.nBufferCountMin + minUndequeuedBufs) {
+ OMX_U32 newBufferCount = def.nBufferCountMin + minUndequeuedBufs;
def.nBufferCountActual = newBufferCount;
err = mOMX->setParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
-
- if (err == OK) {
- minUndequeuedBufs += extraBuffers;
- break;
- }
-
- CODEC_LOGW("setting nBufferCountActual to %lu failed: %d",
- newBufferCount, err);
- /* exit condition */
- if (extraBuffers == 0) {
+ if (err != OK) {
+ CODEC_LOGE("setting nBufferCountActual to %lu failed: %d",
+ newBufferCount, err);
return err;
}
}
- CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d+1",
- def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs);
err = native_window_set_buffer_count(
mNativeWindow.get(), def.nBufferCountActual);
@@ -3513,6 +3508,31 @@ status_t OMXCodec::setAACFormat(
return OK;
}
+status_t OMXCodec::setAC3Format(int32_t numChannels, int32_t sampleRate) {
+ OMX_AUDIO_PARAM_ANDROID_AC3TYPE def;
+ InitOMXParams(&def);
+ def.nPortIndex = kPortIndexInput;
+
+ status_t err = mOMX->getParameter(
+ mNode,
+ (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3,
+ &def,
+ sizeof(def));
+
+ if (err != OK) {
+ return err;
+ }
+
+ def.nChannels = numChannels;
+ def.nSampleRate = sampleRate;
+
+ return mOMX->setParameter(
+ mNode,
+ (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3,
+ &def,
+ sizeof(def));
+}
+
void OMXCodec::setG711Format(int32_t numChannels) {
CHECK(!mIsEncoder);
setRawAudioFormat(kPortIndexInput, 8000, numChannels);
@@ -4446,6 +4466,17 @@ void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
mOutputFormat->setInt32(kKeyChannelCount, numChannels);
mOutputFormat->setInt32(kKeySampleRate, sampleRate);
mOutputFormat->setInt32(kKeyBitRate, bitRate);
+ } else if (audio_def->eEncoding ==
+ (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidAC3) {
+ mOutputFormat->setCString(
+ kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3);
+ int32_t numChannels, sampleRate, bitRate;
+ inputFormat->findInt32(kKeyChannelCount, &numChannels);
+ inputFormat->findInt32(kKeySampleRate, &sampleRate);
+ inputFormat->findInt32(kKeyBitRate, &bitRate);
+ mOutputFormat->setInt32(kKeyChannelCount, numChannels);
+ mOutputFormat->setInt32(kKeySampleRate, sampleRate);
+ mOutputFormat->setInt32(kKeyBitRate, bitRate);
} else {
CHECK(!"Should not be here. Unknown audio encoding.");
}
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 2c8cf8d..d1afd8b 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -508,6 +508,11 @@ ATSParser::Stream::Stream(
ElementaryStreamQueue::PCM_AUDIO);
break;
+ case STREAMTYPE_AC3:
+ mQueue = new ElementaryStreamQueue(
+ ElementaryStreamQueue::AC3);
+ break;
+
default:
break;
}
@@ -616,6 +621,7 @@ bool ATSParser::Stream::isAudio() const {
case STREAMTYPE_MPEG2_AUDIO:
case STREAMTYPE_MPEG2_AUDIO_ADTS:
case STREAMTYPE_PCM_AUDIO:
+ case STREAMTYPE_AC3:
return true;
default:
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 8a80069..86b025f 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -89,6 +89,10 @@ struct ATSParser : public RefBase {
STREAMTYPE_MPEG2_AUDIO_ADTS = 0x0f,
STREAMTYPE_MPEG4_VIDEO = 0x10,
STREAMTYPE_H264 = 0x1b,
+
+ // From ATSC A/53 Part 3:2009, 6.7.1
+ STREAMTYPE_AC3 = 0x81,
+
STREAMTYPE_PCM_AUDIO = 0x83,
};
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 1960b27..e9252cc 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -57,6 +57,122 @@ void ElementaryStreamQueue::clear(bool clearFormat) {
}
}
+// Parse AC3 header assuming the current ptr is start position of syncframe,
+// update metadata only applicable, and return the payload size
+static unsigned parseAC3SyncFrame(
+ const uint8_t *ptr, size_t size, sp<MetaData> *metaData) {
+ static const unsigned channelCountTable[] = {2, 1, 2, 3, 3, 4, 4, 5};
+ static const unsigned samplingRateTable[] = {48000, 44100, 32000};
+ static const unsigned rates[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256,
+ 320, 384, 448, 512, 576, 640};
+
+ static const unsigned frameSizeTable[19][3] = {
+ { 64, 69, 96 },
+ { 80, 87, 120 },
+ { 96, 104, 144 },
+ { 112, 121, 168 },
+ { 128, 139, 192 },
+ { 160, 174, 240 },
+ { 192, 208, 288 },
+ { 224, 243, 336 },
+ { 256, 278, 384 },
+ { 320, 348, 480 },
+ { 384, 417, 576 },
+ { 448, 487, 672 },
+ { 512, 557, 768 },
+ { 640, 696, 960 },
+ { 768, 835, 1152 },
+ { 896, 975, 1344 },
+ { 1024, 1114, 1536 },
+ { 1152, 1253, 1728 },
+ { 1280, 1393, 1920 },
+ };
+
+ ABitReader bits(ptr, size);
+ unsigned syncStartPos = 0; // in bytes
+ if (bits.numBitsLeft() < 16) {
+ return 0;
+ }
+ if (bits.getBits(16) != 0x0B77) {
+ return 0;
+ }
+
+ if (bits.numBitsLeft() < 16 + 2 + 6 + 5 + 3 + 3) {
+ ALOGV("Not enough bits left for further parsing");
+ return 0;
+ }
+ bits.skipBits(16); // crc1
+
+ unsigned fscod = bits.getBits(2);
+ if (fscod == 3) {
+ ALOGW("Incorrect fscod in AC3 header");
+ return 0;
+ }
+
+ unsigned frmsizecod = bits.getBits(6);
+ if (frmsizecod > 37) {
+ ALOGW("Incorrect frmsizecod in AC3 header");
+ return 0;
+ }
+
+ unsigned bsid = bits.getBits(5);
+ if (bsid > 8) {
+ ALOGW("Incorrect bsid in AC3 header. Possibly E-AC-3?");
+ return 0;
+ }
+
+ unsigned bsmod = bits.getBits(3);
+ unsigned acmod = bits.getBits(3);
+ unsigned cmixlev = 0;
+ unsigned surmixlev = 0;
+ unsigned dsurmod = 0;
+
+ if ((acmod & 1) > 0 && acmod != 1) {
+ if (bits.numBitsLeft() < 2) {
+ return 0;
+ }
+ cmixlev = bits.getBits(2);
+ }
+ if ((acmod & 4) > 0) {
+ if (bits.numBitsLeft() < 2) {
+ return 0;
+ }
+ surmixlev = bits.getBits(2);
+ }
+ if (acmod == 2) {
+ if (bits.numBitsLeft() < 2) {
+ return 0;
+ }
+ dsurmod = bits.getBits(2);
+ }
+
+ if (bits.numBitsLeft() < 1) {
+ return 0;
+ }
+ unsigned lfeon = bits.getBits(1);
+
+ unsigned samplingRate = samplingRateTable[fscod];
+ unsigned payloadSize = frameSizeTable[frmsizecod >> 1][fscod];
+ if (fscod == 1) {
+ payloadSize += frmsizecod & 1;
+ }
+ payloadSize <<= 1; // convert from 16-bit words to bytes
+
+ unsigned channelCount = channelCountTable[acmod] + lfeon;
+
+ if (metaData != NULL) {
+ (*metaData)->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3);
+ (*metaData)->setInt32(kKeyChannelCount, channelCount);
+ (*metaData)->setInt32(kKeySampleRate, samplingRate);
+ }
+
+ return payloadSize;
+}
+
+static bool IsSeeminglyValidAC3Header(const uint8_t *ptr, size_t size) {
+ return parseAC3SyncFrame(ptr, size, NULL) > 0;
+}
+
static bool IsSeeminglyValidADTSHeader(const uint8_t *ptr, size_t size) {
if (size < 3) {
// Not enough data to verify header.
@@ -225,6 +341,33 @@ status_t ElementaryStreamQueue::appendData(
break;
}
+ case AC3:
+ {
+ uint8_t *ptr = (uint8_t *)data;
+
+ ssize_t startOffset = -1;
+ for (size_t i = 0; i < size; ++i) {
+ if (IsSeeminglyValidAC3Header(&ptr[i], size - i)) {
+ startOffset = i;
+ break;
+ }
+ }
+
+ if (startOffset < 0) {
+ return ERROR_MALFORMED;
+ }
+
+ if (startOffset > 0) {
+ ALOGI("found something resembling an AC3 syncword at "
+ "offset %d",
+ startOffset);
+ }
+
+ data = &ptr[startOffset];
+ size -= startOffset;
+ break;
+ }
+
case MPEG_AUDIO:
{
uint8_t *ptr = (uint8_t *)data;
@@ -329,6 +472,8 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
return dequeueAccessUnitH264();
case AAC:
return dequeueAccessUnitAAC();
+ case AC3:
+ return dequeueAccessUnitAC3();
case MPEG_VIDEO:
return dequeueAccessUnitMPEGVideo();
case MPEG4_VIDEO:
@@ -341,6 +486,51 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
}
}
+sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAC3() {
+ unsigned syncStartPos = 0; // in bytes
+ unsigned payloadSize = 0;
+ sp<MetaData> format = new MetaData;
+ while (true) {
+ if (syncStartPos + 2 >= mBuffer->size()) {
+ return NULL;
+ }
+
+ payloadSize = parseAC3SyncFrame(
+ mBuffer->data() + syncStartPos,
+ mBuffer->size() - syncStartPos,
+ &format);
+ if (payloadSize > 0) {
+ break;
+ }
+ ++syncStartPos;
+ }
+
+ if (mBuffer->size() < syncStartPos + payloadSize) {
+ ALOGV("Not enough buffer size for AC3");
+ return NULL;
+ }
+
+ if (mFormat == NULL) {
+ mFormat = format;
+ }
+
+ sp<ABuffer> accessUnit = new ABuffer(syncStartPos + payloadSize);
+ memcpy(accessUnit->data(), mBuffer->data(), syncStartPos + payloadSize);
+
+ int64_t timeUs = fetchTimestamp(syncStartPos + payloadSize);
+ CHECK_GE(timeUs, 0ll);
+ accessUnit->meta()->setInt64("timeUs", timeUs);
+
+ memmove(
+ mBuffer->data(),
+ mBuffer->data() + syncStartPos + payloadSize,
+ mBuffer->size() - syncStartPos - payloadSize);
+
+ mBuffer->setRange(0, mBuffer->size() - syncStartPos - payloadSize);
+
+ return accessUnit;
+}
+
sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitPCMAudio() {
if (mBuffer->size() < 4) {
return NULL;
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index 66a8087..a2cca77 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -32,6 +32,7 @@ struct ElementaryStreamQueue {
enum Mode {
H264,
AAC,
+ AC3,
MPEG_AUDIO,
MPEG_VIDEO,
MPEG4_VIDEO,
@@ -67,6 +68,7 @@ private:
sp<ABuffer> dequeueAccessUnitH264();
sp<ABuffer> dequeueAccessUnitAAC();
+ sp<ABuffer> dequeueAccessUnitAC3();
sp<ABuffer> dequeueAccessUnitMPEGAudio();
sp<ABuffer> dequeueAccessUnitMPEGVideo();
sp<ABuffer> dequeueAccessUnitMPEG4Video();