summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camera/ICameraService.cpp59
-rw-r--r--include/camera/ICameraService.h20
-rw-r--r--include/media/AudioSystem.h2
-rw-r--r--include/media/stagefright/MediaDefs.h2
-rw-r--r--media/libmedia/AudioRecord.cpp5
-rw-r--r--media/libmedia/AudioSystem.cpp18
-rw-r--r--media/libmedia/AudioTrack.cpp15
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp8
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.h3
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp178
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.h9
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp268
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h30
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerSource.h8
-rw-r--r--media/libstagefright/MediaDefs.cpp2
-rw-r--r--media/libstagefright/httplive/LiveSession.cpp8
-rw-r--r--media/libstagefright/httplive/LiveSession.h3
-rw-r--r--media/libstagefright/httplive/M3UParser.cpp77
-rw-r--r--media/libstagefright/httplive/M3UParser.h3
-rw-r--r--media/libstagefright/mpeg2ts/ESQueue.cpp6
-rwxr-xr-xservices/audioflinger/Threads.cpp13
-rw-r--r--services/audioflinger/Tracks.cpp4
-rw-r--r--services/camera/libcameraservice/CameraService.cpp185
-rw-r--r--services/camera/libcameraservice/CameraService.h17
24 files changed, 814 insertions, 129 deletions
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index b86651f..79c33f9 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "BpCameraService"
#include <utils/Log.h>
#include <utils/Errors.h>
+#include <utils/String16.h>
#include <stdint.h>
#include <sys/types.h>
@@ -253,6 +254,41 @@ public:
if (readExceptionCode(reply)) return -EPROTO;
return reply.readInt32();
}
+
+ virtual status_t getLegacyParameters(int cameraId, String16* parameters) {
+ if (parameters == NULL) {
+ ALOGE("%s: parameters must not be null", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ Parcel data, reply;
+
+ data.writeInt32(cameraId);
+ remote()->transact(BnCameraService::GET_LEGACY_PARAMETERS, data, &reply);
+ if (readExceptionCode(reply)) return -EPROTO;
+
+ status_t res = data.readInt32();
+ int32_t length = data.readInt32(); // -1 means null
+ if (length > 0) {
+ *parameters = data.readString16();
+ } else {
+ *parameters = String16();
+ }
+
+ return res;
+ }
+
+ virtual status_t supportsCameraApi(int cameraId, int apiVersion) {
+ Parcel data, reply;
+
+ data.writeInt32(cameraId);
+ data.writeInt32(apiVersion);
+ remote()->transact(BnCameraService::SUPPORTS_CAMERA_API, data, &reply);
+ if (readExceptionCode(reply)) return -EPROTO;
+
+ status_t res = data.readInt32();
+ return res;
+ }
};
IMPLEMENT_META_INTERFACE(CameraService, "android.hardware.ICameraService");
@@ -387,6 +423,29 @@ status_t BnCameraService::onTransact(
reply->writeInt32(removeListener(listener));
return NO_ERROR;
} break;
+ case GET_LEGACY_PARAMETERS: {
+ CHECK_INTERFACE(ICameraService, data, reply);
+ int cameraId = data.readInt32();
+ String16 parameters;
+
+ reply->writeNoException();
+ // return value
+ reply->writeInt32(getLegacyParameters(cameraId, &parameters));
+ // out parameters
+ reply->writeInt32(1); // parameters is always available
+ reply->writeString16(parameters);
+ return NO_ERROR;
+ } break;
+ case SUPPORTS_CAMERA_API: {
+ CHECK_INTERFACE(ICameraService, data, reply);
+ int cameraId = data.readInt32();
+ int apiVersion = data.readInt32();
+
+ reply->writeNoException();
+ // return value
+ reply->writeInt32(supportsCameraApi(cameraId, apiVersion));
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h
index 6e48f22..d7e5dac 100644
--- a/include/camera/ICameraService.h
+++ b/include/camera/ICameraService.h
@@ -32,6 +32,7 @@ class ICameraDeviceUser;
class ICameraDeviceCallbacks;
class CameraMetadata;
class VendorTagDescriptor;
+class String16;
class ICameraService : public IInterface
{
@@ -49,12 +50,19 @@ public:
REMOVE_LISTENER,
GET_CAMERA_CHARACTERISTICS,
GET_CAMERA_VENDOR_TAG_DESCRIPTOR,
+ GET_LEGACY_PARAMETERS,
+ SUPPORTS_CAMERA_API,
};
enum {
USE_CALLING_UID = -1
};
+ enum {
+ API_VERSION_1 = 1,
+ API_VERSION_2 = 2,
+ };
+
public:
DECLARE_META_INTERFACE(CameraService);
@@ -105,6 +113,18 @@ public:
int clientUid,
/*out*/
sp<ICameraDeviceUser>& device) = 0;
+
+ virtual status_t getLegacyParameters(
+ int cameraId,
+ /*out*/
+ String16* parameters) = 0;
+
+ /**
+ * Returns OK if device supports camera2 api,
+ * returns -EOPNOTSUPP if it doesn't.
+ */
+ virtual status_t supportsCameraApi(
+ int cameraId, int apiVersion) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 6fe0c7f..a4722cb 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -104,12 +104,10 @@ public:
static status_t getOutputLatency(uint32_t* latency,
audio_stream_type_t stream);
static status_t getSamplingRate(audio_io_handle_t output,
- audio_stream_type_t streamType,
uint32_t* samplingRate);
// returns the number of frames per audio HAL write buffer. Corresponds to
// audio_stream->get_buffer_size()/audio_stream_frame_size()
static status_t getFrameCount(audio_io_handle_t output,
- audio_stream_type_t stream,
size_t* frameCount);
// returns the audio output stream latency in ms. Corresponds to
// audio_stream_out->get_latency()
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 563c0b5..e67d4d5 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -60,6 +60,8 @@ extern const char *MEDIA_MIMETYPE_CONTAINER_WVM;
extern const char *MEDIA_MIMETYPE_TEXT_3GPP;
extern const char *MEDIA_MIMETYPE_TEXT_SUBRIP;
+extern const char *MEDIA_MIMETYPE_TEXT_VTT;
+extern const char *MEDIA_MIMETYPE_TEXT_CEA_608;
} // namespace android
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index db61e85..50b444a 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -105,6 +105,8 @@ AudioRecord::~AudioRecord()
}
mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this);
mAudioRecord.clear();
+ mCblkMemory.clear();
+ mBufferMemory.clear();
IPCThreadState::self()->flushCommands();
AudioSystem::releaseAudioSessionId(mSessionId, -1);
}
@@ -546,9 +548,10 @@ status_t AudioRecord::openRecord_l(size_t epoch)
mDeathNotifier.clear();
}
mAudioRecord = record;
-
mCblkMemory = iMem;
mBufferMemory = bufferMem;
+ IPCThreadState::self()->flushCommands();
+
mCblk = cblk;
// note that temp is the (possibly revised) value of frameCount
if (temp < frameCount || (frameCount == 0 && temp == 0)) {
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index eafb3ad..15b32ff 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -242,11 +242,10 @@ status_t AudioSystem::getOutputSamplingRate(uint32_t* samplingRate, audio_stream
return PERMISSION_DENIED;
}
- return getSamplingRate(output, streamType, samplingRate);
+ return getSamplingRate(output, samplingRate);
}
status_t AudioSystem::getSamplingRate(audio_io_handle_t output,
- audio_stream_type_t streamType,
uint32_t* samplingRate)
{
OutputDescriptor *outputDesc;
@@ -265,13 +264,11 @@ status_t AudioSystem::getSamplingRate(audio_io_handle_t output,
gLock.unlock();
}
if (*samplingRate == 0) {
- ALOGE("AudioSystem::getSamplingRate failed for output %d stream type %d",
- output, streamType);
+ ALOGE("AudioSystem::getSamplingRate failed for output %d", output);
return BAD_VALUE;
}
- ALOGV("getSamplingRate() streamType %d, output %d, sampling rate %u", streamType, output,
- *samplingRate);
+ ALOGV("getSamplingRate() output %d, sampling rate %u", output, *samplingRate);
return NO_ERROR;
}
@@ -289,11 +286,10 @@ status_t AudioSystem::getOutputFrameCount(size_t* frameCount, audio_stream_type_
return PERMISSION_DENIED;
}
- return getFrameCount(output, streamType, frameCount);
+ return getFrameCount(output, frameCount);
}
status_t AudioSystem::getFrameCount(audio_io_handle_t output,
- audio_stream_type_t streamType,
size_t* frameCount)
{
OutputDescriptor *outputDesc;
@@ -310,13 +306,11 @@ status_t AudioSystem::getFrameCount(audio_io_handle_t output,
gLock.unlock();
}
if (*frameCount == 0) {
- ALOGE("AudioSystem::getFrameCount failed for output %d stream type %d",
- output, streamType);
+ ALOGE("AudioSystem::getFrameCount failed for output %d", output);
return BAD_VALUE;
}
- ALOGV("getFrameCount() streamType %d, output %d, frameCount %d", streamType, output,
- *frameCount);
+ ALOGV("getFrameCount() output %d, frameCount %d", output, *frameCount);
return NO_ERROR;
}
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 7d3ecc5..e6827ee 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -174,6 +174,8 @@ AudioTrack::~AudioTrack()
}
mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
mAudioTrack.clear();
+ mCblkMemory.clear();
+ mSharedBuffer.clear();
IPCThreadState::self()->flushCommands();
ALOGV("~AudioTrack, releasing session id from %d on behalf of %d",
IPCThreadState::self()->getCallingPid(), mClientPid);
@@ -647,7 +649,7 @@ uint32_t AudioTrack::getSampleRate() const
if (isOffloaded_l()) {
if (mOutput != AUDIO_IO_HANDLE_NONE) {
uint32_t sampleRate = 0;
- status_t status = AudioSystem::getSamplingRate(mOutput, mStreamType, &sampleRate);
+ status_t status = AudioSystem::getSamplingRate(mOutput, &sampleRate);
if (status == NO_ERROR) {
mSampleRate = sampleRate;
}
@@ -887,16 +889,16 @@ status_t AudioTrack::createTrack_l(size_t epoch)
}
size_t afFrameCount;
- status = AudioSystem::getFrameCount(output, mStreamType, &afFrameCount);
+ status = AudioSystem::getFrameCount(output, &afFrameCount);
if (status != NO_ERROR) {
- ALOGE("getFrameCount(output=%d, streamType=%d) status %d", output, mStreamType, status);
+ ALOGE("getFrameCount(output=%d) status %d", output, status);
goto release;
}
uint32_t afSampleRate;
- status = AudioSystem::getSamplingRate(output, mStreamType, &afSampleRate);
+ status = AudioSystem::getSamplingRate(output, &afSampleRate);
if (status != NO_ERROR) {
- ALOGE("getSamplingRate(output=%d, streamType=%d) status %d", output, mStreamType, status);
+ ALOGE("getSamplingRate(output=%d) status %d", output, status);
goto release;
}
@@ -1059,8 +1061,9 @@ status_t AudioTrack::createTrack_l(size_t epoch)
mDeathNotifier.clear();
}
mAudioTrack = track;
-
mCblkMemory = iMem;
+ IPCThreadState::self()->flushCommands();
+
audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
mCblk = cblk;
// note that temp is the (possibly revised) value of frameCount
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index cbedf5c..e8431e9 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -120,8 +120,12 @@ status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) {
return mLiveSession->getDuration(durationUs);
}
-status_t NuPlayer::HTTPLiveSource::getTrackInfo(Parcel *reply) const {
- return mLiveSession->getTrackInfo(reply);
+size_t NuPlayer::HTTPLiveSource::getTrackCount() const {
+ return mLiveSession->getTrackCount();
+}
+
+sp<AMessage> NuPlayer::HTTPLiveSource::getTrackInfo(size_t trackIndex) const {
+ return mLiveSession->getTrackInfo(trackIndex);
}
status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select) {
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index 4d7251f..6b5f6af 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -40,7 +40,8 @@ struct NuPlayer::HTTPLiveSource : public NuPlayer::Source {
virtual status_t feedMoreTSData();
virtual status_t getDuration(int64_t *durationUs);
- virtual status_t getTrackInfo(Parcel *reply) const;
+ virtual size_t getTrackCount() const;
+ virtual sp<AMessage> getTrackInfo(size_t trackIndex) const;
virtual status_t selectTrack(size_t trackIndex, bool select);
virtual status_t seekTo(int64_t seekTimeUs);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 857e703..b333043 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -305,6 +305,34 @@ bool NuPlayer::IsFlushingState(FlushStatus state, bool *needShutdown) {
}
}
+void NuPlayer::writeTrackInfo(
+ Parcel* reply, const sp<AMessage> format) const {
+ int32_t trackType;
+ CHECK(format->findInt32("type", &trackType));
+
+ AString lang;
+ CHECK(format->findString("language", &lang));
+
+ reply->writeInt32(2); // write something non-zero
+ reply->writeInt32(trackType);
+ reply->writeString16(String16(lang.c_str()));
+
+ if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
+ AString mime;
+ CHECK(format->findString("mime", &mime));
+
+ int32_t isAuto, isDefault, isForced;
+ CHECK(format->findInt32("auto", &isAuto));
+ CHECK(format->findInt32("default", &isDefault));
+ CHECK(format->findInt32("forced", &isForced));
+
+ reply->writeString16(String16(mime.c_str()));
+ reply->writeInt32(isAuto);
+ reply->writeInt32(isDefault);
+ reply->writeInt32(isForced);
+ }
+}
+
void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatSetDataSource:
@@ -339,16 +367,33 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
uint32_t replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
- status_t err = INVALID_OPERATION;
+ Parcel* reply;
+ CHECK(msg->findPointer("reply", (void**)&reply));
+
+ size_t inbandTracks = 0;
if (mSource != NULL) {
- Parcel* reply;
- CHECK(msg->findPointer("reply", (void**)&reply));
- err = mSource->getTrackInfo(reply);
+ inbandTracks = mSource->getTrackCount();
}
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
+ size_t ccTracks = 0;
+ if (mCCDecoder != NULL) {
+ ccTracks = mCCDecoder->getTrackCount();
+ }
+
+ // total track count
+ reply->writeInt32(inbandTracks + ccTracks);
+
+ // write inband tracks
+ for (size_t i = 0; i < inbandTracks; ++i) {
+ writeTrackInfo(reply, mSource->getTrackInfo(i));
+ }
+ // write CC track
+ for (size_t i = 0; i < ccTracks; ++i) {
+ writeTrackInfo(reply, mCCDecoder->getTrackInfo(i));
+ }
+
+ sp<AMessage> response = new AMessage;
response->postReply(replyID);
break;
}
@@ -358,13 +403,30 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
uint32_t replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
+ size_t trackIndex;
+ int32_t select;
+ CHECK(msg->findSize("trackIndex", &trackIndex));
+ CHECK(msg->findInt32("select", &select));
+
status_t err = INVALID_OPERATION;
+
+ size_t inbandTracks = 0;
if (mSource != NULL) {
- size_t trackIndex;
- int32_t select;
- CHECK(msg->findSize("trackIndex", &trackIndex));
- CHECK(msg->findInt32("select", &select));
+ inbandTracks = mSource->getTrackCount();
+ }
+ size_t ccTracks = 0;
+ if (mCCDecoder != NULL) {
+ ccTracks = mCCDecoder->getTrackCount();
+ }
+
+ if (trackIndex < inbandTracks) {
err = mSource->selectTrack(trackIndex, select);
+ } else {
+ trackIndex -= inbandTracks;
+
+ if (trackIndex < ccTracks) {
+ err = mCCDecoder->selectTrack(trackIndex, select);
+ }
}
sp<AMessage> response = new AMessage;
@@ -828,6 +890,12 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
break;
}
+ case kWhatClosedCaptionNotify:
+ {
+ onClosedCaptionNotify(msg);
+ break;
+ }
+
default:
TRESPASS();
break;
@@ -891,6 +959,9 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) {
AString mime;
CHECK(format->findString("mime", &mime));
mVideoIsAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str());
+
+ sp<AMessage> ccNotify = new AMessage(kWhatClosedCaptionNotify, id());
+ mCCDecoder = new CCDecoder(ccNotify);
}
sp<AMessage> notify =
@@ -1031,6 +1102,10 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) {
mediaTimeUs / 1E6);
#endif
+ if (!audio) {
+ mCCDecoder->decode(accessUnit);
+ }
+
reply->setBuffer("buffer", accessUnit);
reply->post();
@@ -1059,14 +1134,15 @@ void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) {
sp<ABuffer> buffer;
CHECK(msg->findBuffer("buffer", &buffer));
+ int64_t mediaTimeUs;
+ CHECK(buffer->meta()->findInt64("timeUs", &mediaTimeUs));
+
int64_t &skipUntilMediaTimeUs =
audio
? mSkipRenderingAudioUntilMediaTimeUs
: mSkipRenderingVideoUntilMediaTimeUs;
if (skipUntilMediaTimeUs >= 0) {
- int64_t mediaTimeUs;
- CHECK(buffer->meta()->findInt64("timeUs", &mediaTimeUs));
if (mediaTimeUs < skipUntilMediaTimeUs) {
ALOGV("dropping %s buffer at time %lld as requested.",
@@ -1080,6 +1156,10 @@ void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) {
skipUntilMediaTimeUs = -1;
}
+ if (!audio && mCCDecoder->isSelected()) {
+ mCCDecoder->display(mediaTimeUs);
+ }
+
mRenderer->queueBuffer(audio, buffer, reply);
}
@@ -1187,6 +1267,14 @@ status_t NuPlayer::selectTrack(size_t trackIndex, bool select) {
sp<AMessage> response;
status_t err = msg->postAndAwaitResponse(&response);
+ if (err != OK) {
+ return err;
+ }
+
+ if (!response->findInt32("err", &err)) {
+ err = OK;
+ }
+
return err;
}
@@ -1438,21 +1526,7 @@ void NuPlayer::onSourceNotify(const sp<AMessage> &msg) {
sp<ABuffer> buffer;
CHECK(msg->findBuffer("buffer", &buffer));
- int32_t trackIndex;
- int64_t timeUs, durationUs;
- CHECK(buffer->meta()->findInt32("trackIndex", &trackIndex));
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- CHECK(buffer->meta()->findInt64("durationUs", &durationUs));
-
- Parcel in;
- in.writeInt32(trackIndex);
- in.writeInt64(timeUs);
- in.writeInt64(durationUs);
- in.writeInt32(buffer->size());
- in.writeInt32(buffer->size());
- in.write(buffer->data(), buffer->size());
-
- notifyListener(MEDIA_SUBTITLE_DATA, 0, 0, &in);
+ sendSubtitleData(buffer, 0 /* baseIndex */);
break;
}
@@ -1474,6 +1548,56 @@ void NuPlayer::onSourceNotify(const sp<AMessage> &msg) {
}
}
+void NuPlayer::onClosedCaptionNotify(const sp<AMessage> &msg) {
+ int32_t what;
+ CHECK(msg->findInt32("what", &what));
+
+ switch (what) {
+ case NuPlayer::CCDecoder::kWhatClosedCaptionData:
+ {
+ sp<ABuffer> buffer;
+ CHECK(msg->findBuffer("buffer", &buffer));
+
+ size_t inbandTracks = 0;
+ if (mSource != NULL) {
+ inbandTracks = mSource->getTrackCount();
+ }
+
+ sendSubtitleData(buffer, inbandTracks);
+ break;
+ }
+
+ case NuPlayer::CCDecoder::kWhatTrackAdded:
+ {
+ notifyListener(MEDIA_INFO, MEDIA_INFO_METADATA_UPDATE, 0);
+
+ break;
+ }
+
+ default:
+ TRESPASS();
+ }
+
+
+}
+
+void NuPlayer::sendSubtitleData(const sp<ABuffer> &buffer, int32_t baseIndex) {
+ int32_t trackIndex;
+ int64_t timeUs, durationUs;
+ CHECK(buffer->meta()->findInt32("trackIndex", &trackIndex));
+ CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
+ CHECK(buffer->meta()->findInt64("durationUs", &durationUs));
+
+ Parcel in;
+ in.writeInt32(trackIndex + baseIndex);
+ in.writeInt64(timeUs);
+ in.writeInt64(durationUs);
+ in.writeInt32(buffer->size());
+ in.writeInt32(buffer->size());
+ in.write(buffer->data(), buffer->size());
+
+ notifyListener(MEDIA_SUBTITLE_DATA, 0, 0, &in);
+}
////////////////////////////////////////////////////////////////////////////////
void NuPlayer::Source::notifyFlagsChanged(uint32_t flags) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index f1d3d55..5be71fb 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -24,6 +24,7 @@
namespace android {
+struct ABuffer;
struct MetaData;
struct NuPlayerDriver;
@@ -75,6 +76,7 @@ public:
private:
struct Decoder;
+ struct CCDecoder;
struct GenericSource;
struct HTTPLiveSource;
struct Renderer;
@@ -97,6 +99,7 @@ private:
kWhatScanSources = 'scan',
kWhatVideoNotify = 'vidN',
kWhatAudioNotify = 'audN',
+ kWhatClosedCaptionNotify = 'capN',
kWhatRendererNotify = 'renN',
kWhatReset = 'rset',
kWhatSeek = 'seek',
@@ -118,6 +121,7 @@ private:
sp<Decoder> mVideoDecoder;
bool mVideoIsAVC;
sp<Decoder> mAudioDecoder;
+ sp<CCDecoder> mCCDecoder;
sp<Renderer> mRenderer;
List<sp<Action> > mDeferredActions;
@@ -185,10 +189,15 @@ private:
void performSetSurface(const sp<NativeWindowWrapper> &wrapper);
void onSourceNotify(const sp<AMessage> &msg);
+ void onClosedCaptionNotify(const sp<AMessage> &msg);
void queueDecoderShutdown(
bool audio, bool video, const sp<AMessage> &reply);
+ void sendSubtitleData(const sp<ABuffer> &buffer, int32_t baseIndex);
+
+ void writeTrackInfo(Parcel* reply, const sp<AMessage> format) const;
+
DISALLOW_EVIL_CONSTRUCTORS(NuPlayer);
};
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index cfbf282..5abfb71 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -22,6 +22,7 @@
#include "NuPlayerDecoder.h"
#include <media/ICrypto.h>
+#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -535,5 +536,272 @@ bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetF
return seamless;
}
+struct NuPlayer::CCDecoder::CCData {
+ CCData(uint8_t type, uint8_t data1, uint8_t data2)
+ : mType(type), mData1(data1), mData2(data2) {
+ }
+
+ uint8_t mType;
+ uint8_t mData1;
+ uint8_t mData2;
+};
+
+NuPlayer::CCDecoder::CCDecoder(const sp<AMessage> &notify)
+ : mNotify(notify),
+ mTrackCount(0),
+ mSelectedTrack(-1) {
+}
+
+size_t NuPlayer::CCDecoder::getTrackCount() const {
+ return mTrackCount;
+}
+
+sp<AMessage> NuPlayer::CCDecoder::getTrackInfo(size_t index) const {
+ CHECK(index == 0);
+
+ sp<AMessage> format = new AMessage();
+
+ format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE);
+ format->setString("language", "und");
+ format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
+ format->setInt32("auto", 1);
+ format->setInt32("default", 1);
+ format->setInt32("forced", 0);
+
+ return format;
+}
+
+status_t NuPlayer::CCDecoder::selectTrack(size_t index, bool select) {
+ CHECK(index < mTrackCount);
+
+ if (select) {
+ if (mSelectedTrack == (ssize_t)index) {
+ ALOGE("track %zu already selected", index);
+ return BAD_VALUE;
+ }
+ ALOGV("selected track %zu", index);
+ mSelectedTrack = index;
+ } else {
+ if (mSelectedTrack != (ssize_t)index) {
+ ALOGE("track %zu is not selected", index);
+ return BAD_VALUE;
+ }
+ ALOGV("unselected track %zu", index);
+ mSelectedTrack = -1;
+ }
+
+ return OK;
+}
+
+bool NuPlayer::CCDecoder::isSelected() const {
+ return mSelectedTrack >= 0 && mSelectedTrack < (int32_t)mTrackCount;
+}
+
+bool NuPlayer::CCDecoder::isNullPad(CCData *cc) const {
+ return cc->mData1 < 0x10 && cc->mData2 < 0x10;
+}
+
+void NuPlayer::CCDecoder::dumpBytePair(const sp<ABuffer> &ccBuf) const {
+ size_t offset = 0;
+ AString out;
+
+ while (offset < ccBuf->size()) {
+ char tmp[128];
+
+ CCData *cc = (CCData *) (ccBuf->data() + offset);
+
+ if (isNullPad(cc)) {
+ // 1 null pad or XDS metadata, ignore
+ offset += sizeof(CCData);
+ continue;
+ }
+
+ if (cc->mData1 >= 0x20 && cc->mData1 <= 0x7f) {
+ // 2 basic chars
+ sprintf(tmp, "[%d]Basic: %c %c", cc->mType, cc->mData1, cc->mData2);
+ } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
+ && cc->mData2 >= 0x30 && cc->mData2 <= 0x3f) {
+ // 1 special char
+ sprintf(tmp, "[%d]Special: %02x %02x", cc->mType, cc->mData1, cc->mData2);
+ } else if ((cc->mData1 == 0x12 || cc->mData1 == 0x1A)
+ && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
+ // 1 Spanish/French char
+ sprintf(tmp, "[%d]Spanish: %02x %02x", cc->mType, cc->mData1, cc->mData2);
+ } else if ((cc->mData1 == 0x13 || cc->mData1 == 0x1B)
+ && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
+ // 1 Portuguese/German/Danish char
+ sprintf(tmp, "[%d]German: %02x %02x", cc->mType, cc->mData1, cc->mData2);
+ } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
+ && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f){
+ // Mid-Row Codes (Table 69)
+ sprintf(tmp, "[%d]Mid-row: %02x %02x", cc->mType, cc->mData1, cc->mData2);
+ } else if (((cc->mData1 == 0x14 || cc->mData1 == 0x1c)
+ && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f)
+ ||
+ ((cc->mData1 == 0x17 || cc->mData1 == 0x1f)
+ && cc->mData2 >= 0x21 && cc->mData2 <= 0x23)){
+ // Misc Control Codes (Table 70)
+ sprintf(tmp, "[%d]Ctrl: %02x %02x", cc->mType, cc->mData1, cc->mData2);
+ } else if ((cc->mData1 & 0x70) == 0x10
+ && (cc->mData2 & 0x40) == 0x40
+ && ((cc->mData1 & 0x07) || !(cc->mData2 & 0x20)) ) {
+ // Preamble Address Codes (Table 71)
+ sprintf(tmp, "[%d]PAC: %02x %02x", cc->mType, cc->mData1, cc->mData2);
+ } else {
+ sprintf(tmp, "[%d]Invalid: %02x %02x", cc->mType, cc->mData1, cc->mData2);
+ }
+
+ if (out.size() > 0) {
+ out.append(", ");
+ }
+
+ out.append(tmp);
+
+ offset += sizeof(CCData);
+ }
+
+ ALOGI("%s", out.c_str());
+}
+
+bool NuPlayer::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) {
+ int64_t timeUs;
+ CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
+
+ sp<ABuffer> sei;
+ if (!accessUnit->meta()->findBuffer("sei", &sei) || sei == NULL) {
+ return false;
+ }
+
+ bool hasCC = false;
+
+ ABitReader br(sei->data() + 1, sei->size() - 1);
+ // sei_message()
+ while (br.numBitsLeft() >= 16) { // at least 16-bit for sei_message()
+ uint32_t payload_type = 0;
+ size_t payload_size = 0;
+ uint8_t last_byte;
+
+ do {
+ last_byte = br.getBits(8);
+ payload_type += last_byte;
+ } while (last_byte == 0xFF);
+
+ do {
+ last_byte = br.getBits(8);
+ payload_size += last_byte;
+ } while (last_byte == 0xFF);
+
+ // sei_payload()
+ if (payload_type == 4) {
+ // user_data_registered_itu_t_t35()
+
+ // ATSC A/72: 6.4.2
+ uint8_t itu_t_t35_country_code = br.getBits(8);
+ uint16_t itu_t_t35_provider_code = br.getBits(16);
+ uint32_t user_identifier = br.getBits(32);
+ uint8_t user_data_type_code = br.getBits(8);
+
+ payload_size -= 1 + 2 + 4 + 1;
+
+ if (itu_t_t35_country_code == 0xB5
+ && itu_t_t35_provider_code == 0x0031
+ && user_identifier == 'GA94'
+ && user_data_type_code == 0x3) {
+ hasCC = true;
+
+ // MPEG_cc_data()
+ // ATSC A/53 Part 4: 6.2.3.1
+ br.skipBits(1); //process_em_data_flag
+ bool process_cc_data_flag = br.getBits(1);
+ br.skipBits(1); //additional_data_flag
+ size_t cc_count = br.getBits(5);
+ br.skipBits(8); // em_data;
+ payload_size -= 2;
+
+ if (process_cc_data_flag) {
+ AString out;
+
+ sp<ABuffer> ccBuf = new ABuffer(cc_count * sizeof(CCData));
+ ccBuf->setRange(0, 0);
+
+ for (size_t i = 0; i < cc_count; i++) {
+ uint8_t marker = br.getBits(5);
+ CHECK_EQ(marker, 0x1f);
+
+ bool cc_valid = br.getBits(1);
+ uint8_t cc_type = br.getBits(2);
+ // remove odd parity bit
+ uint8_t cc_data_1 = br.getBits(8) & 0x7f;
+ uint8_t cc_data_2 = br.getBits(8) & 0x7f;
+
+ if (cc_valid
+ && (cc_type == 0 || cc_type == 1)) {
+ CCData cc(cc_type, cc_data_1, cc_data_2);
+ if (!isNullPad(&cc)) {
+ memcpy(ccBuf->data() + ccBuf->size(),
+ (void *)&cc, sizeof(cc));
+ ccBuf->setRange(0, ccBuf->size() + sizeof(CCData));
+ }
+ }
+ }
+ payload_size -= cc_count * 3;
+
+ mCCMap.add(timeUs, ccBuf);
+ break;
+ }
+ } else {
+ ALOGV("Malformed SEI payload type 4");
+ }
+ } else {
+ ALOGV("Unsupported SEI payload type %d", payload_type);
+ }
+
+ // skipping remaining bits of this payload
+ br.skipBits(payload_size * 8);
+ }
+
+ return hasCC;
+}
+
+void NuPlayer::CCDecoder::decode(const sp<ABuffer> &accessUnit) {
+ if (extractFromSEI(accessUnit) && mTrackCount == 0) {
+ mTrackCount++;
+
+ ALOGI("Found CEA-608 track");
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatTrackAdded);
+ msg->post();
+ }
+ // TODO: extract CC from other sources
+}
+
+void NuPlayer::CCDecoder::display(int64_t timeUs) {
+ ssize_t index = mCCMap.indexOfKey(timeUs);
+ if (index < 0) {
+ ALOGV("cc for timestamp %" PRId64 " not found", timeUs);
+ return;
+ }
+
+ sp<ABuffer> &ccBuf = mCCMap.editValueAt(index);
+
+ if (ccBuf->size() > 0) {
+#if 0
+ dumpBytePair(ccBuf);
+#endif
+
+ ccBuf->meta()->setInt32("trackIndex", mSelectedTrack);
+ ccBuf->meta()->setInt64("timeUs", timeUs);
+ ccBuf->meta()->setInt64("durationUs", 0ll);
+
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatClosedCaptionData);
+ msg->setBuffer("buffer", ccBuf);
+ msg->post();
+ }
+
+ // remove all entries before timeUs
+ mCCMap.removeItemsAt(0, index + 1);
+}
+
} // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index 2892584..1a4f4ab 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -101,6 +101,36 @@ private:
DISALLOW_EVIL_CONSTRUCTORS(Decoder);
};
+struct NuPlayer::CCDecoder : public RefBase {
+ enum {
+ kWhatClosedCaptionData,
+ kWhatTrackAdded,
+ };
+
+ CCDecoder(const sp<AMessage> &notify);
+
+ size_t getTrackCount() const;
+ sp<AMessage> getTrackInfo(size_t index) const;
+ status_t selectTrack(size_t index, bool select);
+ bool isSelected() const;
+ void decode(const sp<ABuffer> &accessUnit);
+ void display(int64_t timeUs);
+
+private:
+ struct CCData;
+
+ sp<AMessage> mNotify;
+ KeyedVector<int64_t, sp<ABuffer> > mCCMap;
+ size_t mTrackCount;
+ int32_t mSelectedTrack;
+
+ bool isNullPad(CCData *cc) const;
+ void dumpBytePair(const sp<ABuffer> &ccBuf) const;
+ bool extractFromSEI(const sp<ABuffer> &accessUnit);
+
+ DISALLOW_EVIL_CONSTRUCTORS(CCDecoder);
+};
+
} // namespace android
#endif // NUPLAYER_DECODER_H_
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 11279fc..f5a1d6d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -72,8 +72,12 @@ struct NuPlayer::Source : public AHandler {
return INVALID_OPERATION;
}
- virtual status_t getTrackInfo(Parcel* /* reply */) const {
- return INVALID_OPERATION;
+ virtual size_t getTrackCount() const {
+ return 0;
+ }
+
+ virtual sp<AMessage> getTrackInfo(size_t /* trackIndex */) const {
+ return NULL;
}
virtual status_t selectTrack(size_t /* trackIndex */, bool /* select */) {
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 8229e55..d48dd84 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -58,5 +58,7 @@ const char *MEDIA_MIMETYPE_CONTAINER_WVM = "video/wvm";
const char *MEDIA_MIMETYPE_TEXT_3GPP = "text/3gpp-tt";
const char *MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
+const char *MEDIA_MIMETYPE_TEXT_VTT = "text/vtt";
+const char *MEDIA_MIMETYPE_TEXT_CEA_608 = "text/cea-608";
} // namespace android
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 08a146f..10cdde2 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -926,8 +926,12 @@ bool LiveSession::hasDynamicDuration() const {
return false;
}
-status_t LiveSession::getTrackInfo(Parcel *reply) const {
- return mPlaylist->getTrackInfo(reply);
+size_t LiveSession::getTrackCount() const {
+ return mPlaylist->getTrackCount();
+}
+
+sp<AMessage> LiveSession::getTrackInfo(size_t trackIndex) const {
+ return mPlaylist->getTrackInfo(trackIndex);
}
status_t LiveSession::selectTrack(size_t index, bool select) {
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index d7ed56f..ed3818f 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -70,7 +70,8 @@ struct LiveSession : public AHandler {
status_t seekTo(int64_t timeUs);
status_t getDuration(int64_t *durationUs) const;
- status_t getTrackInfo(Parcel *reply) const;
+ size_t getTrackCount() const;
+ sp<AMessage> getTrackInfo(size_t trackIndex) const;
status_t selectTrack(size_t index, bool select);
bool isSeekable() const;
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 785c515..281e0da 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -23,6 +23,7 @@
#include <cutils/properties.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
#include <media/mediaplayer.h>
@@ -58,8 +59,8 @@ struct M3UParser::MediaGroup : public RefBase {
void pickRandomMediaItems();
status_t selectTrack(size_t index, bool select);
- void getTrackInfo(Parcel* reply) const;
size_t countTracks() const;
+ sp<AMessage> getTrackInfo(size_t index) const;
protected:
virtual ~MediaGroup();
@@ -184,35 +185,42 @@ status_t M3UParser::MediaGroup::selectTrack(size_t index, bool select) {
return OK;
}
-void M3UParser::MediaGroup::getTrackInfo(Parcel* reply) const {
- for (size_t i = 0; i < mMediaItems.size(); ++i) {
- reply->writeInt32(2); // 2 fields
-
- if (mType == TYPE_AUDIO) {
- reply->writeInt32(MEDIA_TRACK_TYPE_AUDIO);
- } else if (mType == TYPE_VIDEO) {
- reply->writeInt32(MEDIA_TRACK_TYPE_VIDEO);
- } else if (mType == TYPE_SUBS) {
- reply->writeInt32(MEDIA_TRACK_TYPE_SUBTITLE);
- } else {
- reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN);
- }
+size_t M3UParser::MediaGroup::countTracks() const {
+ return mMediaItems.size();
+}
- const Media &item = mMediaItems.itemAt(i);
- const char *lang = item.mLanguage.empty() ? "und" : item.mLanguage.c_str();
- reply->writeString16(String16(lang));
+sp<AMessage> M3UParser::MediaGroup::getTrackInfo(size_t index) const {
+ if (index >= mMediaItems.size()) {
+ return NULL;
+ }
- if (mType == TYPE_SUBS) {
- // TO-DO: pass in a MediaFormat instead
- reply->writeInt32(!!(item.mFlags & MediaGroup::FLAG_AUTOSELECT));
- reply->writeInt32(!!(item.mFlags & MediaGroup::FLAG_DEFAULT));
- reply->writeInt32(!!(item.mFlags & MediaGroup::FLAG_FORCED));
- }
+ sp<AMessage> format = new AMessage();
+
+ int32_t trackType;
+ if (mType == TYPE_AUDIO) {
+ trackType = MEDIA_TRACK_TYPE_AUDIO;
+ } else if (mType == TYPE_VIDEO) {
+ trackType = MEDIA_TRACK_TYPE_VIDEO;
+ } else if (mType == TYPE_SUBS) {
+ trackType = MEDIA_TRACK_TYPE_SUBTITLE;
+ } else {
+ trackType = MEDIA_TRACK_TYPE_UNKNOWN;
+ }
+ format->setInt32("type", trackType);
+
+ const Media &item = mMediaItems.itemAt(index);
+ const char *lang = item.mLanguage.empty() ? "und" : item.mLanguage.c_str();
+ format->setString("language", lang);
+
+ if (mType == TYPE_SUBS) {
+ // TO-DO: pass in a MediaFormat instead
+ format->setString("mime", MEDIA_MIMETYPE_TEXT_VTT);
+ format->setInt32("auto", !!(item.mFlags & MediaGroup::FLAG_AUTOSELECT));
+ format->setInt32("default", !!(item.mFlags & MediaGroup::FLAG_DEFAULT));
+ format->setInt32("forced", !!(item.mFlags & MediaGroup::FLAG_FORCED));
}
-}
-size_t M3UParser::MediaGroup::countTracks() const {
- return mMediaItems.size();
+ return format;
}
bool M3UParser::MediaGroup::getActiveURI(AString *uri) const {
@@ -319,17 +327,24 @@ status_t M3UParser::selectTrack(size_t index, bool select) {
return INVALID_OPERATION;
}
-status_t M3UParser::getTrackInfo(Parcel* reply) const {
+size_t M3UParser::getTrackCount() const {
size_t trackCount = 0;
for (size_t i = 0; i < mMediaGroups.size(); ++i) {
trackCount += mMediaGroups.valueAt(i)->countTracks();
}
- reply->writeInt32(trackCount);
+ return trackCount;
+}
- for (size_t i = 0; i < mMediaGroups.size(); ++i) {
- mMediaGroups.valueAt(i)->getTrackInfo(reply);
+sp<AMessage> M3UParser::getTrackInfo(size_t index) const {
+ for (size_t i = 0, ii = index; i < mMediaGroups.size(); ++i) {
+ sp<MediaGroup> group = mMediaGroups.valueAt(i);
+ size_t tracks = group->countTracks();
+ if (ii < tracks) {
+ return group->getTrackInfo(ii);
+ }
+ ii -= tracks;
}
- return OK;
+ return NULL;
}
ssize_t M3UParser::getSelectedIndex() const {
diff --git a/media/libstagefright/httplive/M3UParser.h b/media/libstagefright/httplive/M3UParser.h
index ccd6556..fe9fb9d 100644
--- a/media/libstagefright/httplive/M3UParser.h
+++ b/media/libstagefright/httplive/M3UParser.h
@@ -42,7 +42,8 @@ struct M3UParser : public RefBase {
void pickRandomMediaItems();
status_t selectTrack(size_t index, bool select);
- status_t getTrackInfo(Parcel* reply) const;
+ size_t getTrackCount() const;
+ sp<AMessage> getTrackInfo(size_t index) const;
ssize_t getSelectedIndex() const;
bool getTypeURI(size_t index, const char *key, AString *uri) const;
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index f7abf01..3c8f03e 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -777,6 +777,12 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() {
unsigned nalType = mBuffer->data()[pos.nalOffset] & 0x1f;
+ if (nalType == 6) {
+ sp<ABuffer> sei = new ABuffer(pos.nalSize);
+ memcpy(sei->data(), mBuffer->data() + pos.nalOffset, pos.nalSize);
+ accessUnit->meta()->setBuffer("sei", sei);
+ }
+
#if !LOG_NDEBUG
char tmp[128];
sprintf(tmp, "0x%02x", nalType);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index c0daa08..d6390b1 100755
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -5139,7 +5139,7 @@ reacquire_wakelock:
sleepUs = kRecordThreadSleepUs;
}
if (framesRead <= 0) {
- continue;
+ goto unlock;
}
ALOG_ASSERT(framesRead > 0);
@@ -5147,10 +5147,12 @@ reacquire_wakelock:
(void) mTeeSink->write(&mRsmpInBuffer[rear * mChannelCount], framesRead);
}
// If destination is non-contiguous, we now correct for reading past end of buffer.
- size_t part1 = mRsmpInFramesP2 - rear;
- if ((size_t) framesRead > part1) {
- memcpy(mRsmpInBuffer, &mRsmpInBuffer[mRsmpInFramesP2 * mChannelCount],
- (framesRead - part1) * mFrameSize);
+ {
+ size_t part1 = mRsmpInFramesP2 - rear;
+ if ((size_t) framesRead > part1) {
+ memcpy(mRsmpInBuffer, &mRsmpInBuffer[mRsmpInFramesP2 * mChannelCount],
+ (framesRead - part1) * mFrameSize);
+ }
}
rear = mRsmpInRear += framesRead;
@@ -5358,6 +5360,7 @@ reacquire_wakelock:
}
+unlock:
// enable changes in effect chain
unlockEffectChains(effectChains);
// effectChains doesn't need to be cleared, since it is cleared by destructor at scope end
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 4e8a058..1e906ad 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -223,6 +223,8 @@ AudioFlinger::ThreadBase::TrackBase::~TrackBase()
// relying on the automatic clear() at end of scope.
mClient.clear();
}
+ // flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
}
// AudioBufferProvider interface
@@ -432,8 +434,6 @@ AudioFlinger::PlaybackThread::Track::~Track()
// This prevents that leak.
if (mSharedBuffer != 0) {
mSharedBuffer.clear();
- // flush the binder command buffer
- IPCThreadState::self()->flushCommands();
}
}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 9fd35e1..73eccbf 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -261,32 +261,20 @@ status_t CameraService::generateShimMetadata(int cameraId, /*out*/CameraMetadata
return ret;
}
- ssize_t index = -1;
- { // Scope for service lock
- Mutex::Autolock lock(mServiceLock);
- index = mShimParams.indexOfKey(cameraId);
- // Release service lock so initializeShimMetadata can be called correctly.
- }
-
- if (index < 0) {
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- ret = initializeShimMetadata(cameraId);
- IPCThreadState::self()->restoreCallingIdentity(token);
- if (ret != OK) {
- return ret;
- }
+ CameraParameters shimParams;
+ if ((ret = getLegacyParametersLazy(cameraId, /*out*/&shimParams)) != OK) {
+ // Error logged by callee
+ return ret;
}
Vector<Size> sizes;
+ Vector<Size> jpegSizes;
Vector<int32_t> formats;
const char* supportedPreviewFormats;
- { // Scope for service lock
- Mutex::Autolock lock(mServiceLock);
- index = mShimParams.indexOfKey(cameraId);
-
- mShimParams[index].getSupportedPreviewSizes(/*out*/sizes);
-
- mShimParams[index].getSupportedPreviewFormats(/*out*/formats);
+ {
+ shimParams.getSupportedPreviewSizes(/*out*/sizes);
+ shimParams.getSupportedPreviewFormats(/*out*/formats);
+ shimParams.getSupportedPictureSizes(/*out*/jpegSizes);
}
// Always include IMPLEMENTATION_DEFINED
@@ -295,21 +283,29 @@ status_t CameraService::generateShimMetadata(int cameraId, /*out*/CameraMetadata
const size_t INTS_PER_CONFIG = 4;
// Build available stream configurations metadata
- size_t streamConfigSize = sizes.size() * formats.size() * INTS_PER_CONFIG;
- int32_t streamConfigs[streamConfigSize];
- size_t configIndex = 0;
+ size_t streamConfigSize = (sizes.size() * formats.size() + jpegSizes.size()) * INTS_PER_CONFIG;
+
+ Vector<int32_t> streamConfigs;
+ streamConfigs.setCapacity(streamConfigSize);
+
for (size_t i = 0; i < formats.size(); ++i) {
for (size_t j = 0; j < sizes.size(); ++j) {
- streamConfigs[configIndex++] = formats[i];
- streamConfigs[configIndex++] = sizes[j].width;
- streamConfigs[configIndex++] = sizes[j].height;
- streamConfigs[configIndex++] =
- ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT;
+ streamConfigs.add(formats[i]);
+ streamConfigs.add(sizes[j].width);
+ streamConfigs.add(sizes[j].height);
+ streamConfigs.add(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
}
}
+ for (size_t i = 0; i < jpegSizes.size(); ++i) {
+ streamConfigs.add(HAL_PIXEL_FORMAT_BLOB);
+ streamConfigs.add(jpegSizes[i].width);
+ streamConfigs.add(jpegSizes[i].height);
+ streamConfigs.add(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
+ }
+
if ((ret = shimInfo.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
- streamConfigs, streamConfigSize)) != OK) {
+ streamConfigs.array(), streamConfigSize)) != OK) {
return ret;
}
@@ -470,6 +466,7 @@ status_t CameraService::initializeShimMetadata(int cameraId) {
int uid = getCallingUid();
status_t ret = validateConnect(cameraId, uid);
if (ret != OK) {
+ // Error already logged by callee
return ret;
}
@@ -492,6 +489,7 @@ status_t CameraService::initializeShimMetadata(int cameraId) {
client);
if (ret != OK) {
+ // Error already logged by callee
return ret;
}
}
@@ -513,6 +511,52 @@ status_t CameraService::initializeShimMetadata(int cameraId) {
return OK;
}
+status_t CameraService::getLegacyParametersLazy(int cameraId,
+ /*out*/
+ CameraParameters* parameters) {
+
+ ALOGV("%s: for cameraId: %d", __FUNCTION__, cameraId);
+
+ status_t ret = 0;
+
+ if (parameters == NULL) {
+ ALOGE("%s: parameters must not be null", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ ssize_t index = -1;
+ { // Scope for service lock
+ Mutex::Autolock lock(mServiceLock);
+ index = mShimParams.indexOfKey(cameraId);
+ // Release service lock so initializeShimMetadata can be called correctly.
+
+ if (index >= 0) {
+ *parameters = mShimParams[index];
+ }
+ }
+
+ if (index < 0) {
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ ret = initializeShimMetadata(cameraId);
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ if (ret != OK) {
+ // Error already logged by callee
+ return ret;
+ }
+
+ { // Scope for service lock
+ Mutex::Autolock lock(mServiceLock);
+ index = mShimParams.indexOfKey(cameraId);
+
+ LOG_ALWAYS_FATAL_IF(index < 0, "index should have been initialized");
+
+ *parameters = mShimParams[index];
+ }
+ }
+
+ return OK;
+}
+
status_t CameraService::validateConnect(int cameraId,
/*inout*/
int& clientUid) const {
@@ -780,8 +824,8 @@ status_t CameraService::connectPro(
case CAMERA_DEVICE_API_VERSION_3_0:
case CAMERA_DEVICE_API_VERSION_3_1:
case CAMERA_DEVICE_API_VERSION_3_2:
- client = new ProCamera2Client(this, cameraCb, String16(),
- cameraId, facing, callingPid, USE_CALLING_UID, getpid());
+ client = new ProCamera2Client(this, cameraCb, clientPackageName,
+ cameraId, facing, callingPid, clientUid, getpid());
break;
case -1:
ALOGE("Invalid camera id %d", cameraId);
@@ -860,8 +904,8 @@ status_t CameraService::connectDevice(
case CAMERA_DEVICE_API_VERSION_3_0:
case CAMERA_DEVICE_API_VERSION_3_1:
case CAMERA_DEVICE_API_VERSION_3_2:
- client = new CameraDeviceClient(this, cameraCb, String16(),
- cameraId, facing, callingPid, USE_CALLING_UID, getpid());
+ client = new CameraDeviceClient(this, cameraCb, clientPackageName,
+ cameraId, facing, callingPid, clientUid, getpid());
break;
case -1:
ALOGE("Invalid camera id %d", cameraId);
@@ -950,6 +994,78 @@ status_t CameraService::removeListener(
return BAD_VALUE;
}
+status_t CameraService::getLegacyParameters(
+ int cameraId,
+ /*out*/
+ String16* parameters) {
+ ALOGV("%s: for camera ID = %d", __FUNCTION__, cameraId);
+
+ if (parameters == NULL) {
+ ALOGE("%s: parameters must not be null", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ status_t ret = 0;
+
+ CameraParameters shimParams;
+ if ((ret = getLegacyParametersLazy(cameraId, /*out*/&shimParams)) != OK) {
+ // Error logged by caller
+ return ret;
+ }
+
+ String8 shimParamsString8 = shimParams.flatten();
+ String16 shimParamsString16 = String16(shimParamsString8);
+
+ *parameters = shimParamsString16;
+
+ return OK;
+}
+
+status_t CameraService::supportsCameraApi(int cameraId, int apiVersion) {
+ ALOGV("%s: for camera ID = %d", __FUNCTION__, cameraId);
+
+ switch (apiVersion) {
+ case API_VERSION_1:
+ case API_VERSION_2:
+ break;
+ default:
+ ALOGE("%s: Bad API version %d", __FUNCTION__, apiVersion);
+ return BAD_VALUE;
+ }
+
+ int facing = -1;
+ int deviceVersion = getDeviceVersion(cameraId, &facing);
+
+ switch(deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_1_0:
+ case CAMERA_DEVICE_API_VERSION_2_0:
+ case CAMERA_DEVICE_API_VERSION_2_1:
+ case CAMERA_DEVICE_API_VERSION_3_0:
+ case CAMERA_DEVICE_API_VERSION_3_1:
+ if (apiVersion == API_VERSION_2) {
+ ALOGV("%s: Camera id %d uses HAL prior to HAL3.2, doesn't support api2 without shim",
+ __FUNCTION__, cameraId);
+ return -EOPNOTSUPP;
+ } else { // if (apiVersion == API_VERSION_1) {
+ ALOGV("%s: Camera id %d uses older HAL before 3.2, but api1 is always supported",
+ __FUNCTION__, cameraId);
+ return OK;
+ }
+ case CAMERA_DEVICE_API_VERSION_3_2:
+ ALOGV("%s: Camera id %d uses HAL3.2 or newer, supports api1/api2 directly",
+ __FUNCTION__, cameraId);
+ return OK;
+ case -1:
+ ALOGE("%s: Invalid camera id %d", __FUNCTION__, cameraId);
+ return BAD_VALUE;
+ default:
+ ALOGE("%s: Unknown camera device HAL version: %d", __FUNCTION__, deviceVersion);
+ return INVALID_OPERATION;
+ }
+
+ return OK;
+}
+
void CameraService::removeClientByRemote(const wp<IBinder>& remoteBinder) {
int callingPid = getCallingPid();
LOG1("CameraService::removeClientByRemote E (pid %d)", callingPid);
@@ -1079,6 +1195,7 @@ status_t CameraService::onTransact(
switch (code) {
case BnCameraService::CONNECT:
case BnCameraService::CONNECT_PRO:
+ case BnCameraService::CONNECT_DEVICE:
const int pid = getCallingPid();
const int self_pid = getpid();
if (pid != self_pid) {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index ee39d52..b2b65b8 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -100,6 +100,15 @@ public:
virtual status_t removeListener(
const sp<ICameraServiceListener>& listener);
+ virtual status_t getLegacyParameters(
+ int cameraId,
+ /*out*/
+ String16* parameters);
+
+ // OK = supports api of that version, -EOPNOTSUPP = does not support
+ virtual status_t supportsCameraApi(
+ int cameraId, int apiVersion);
+
// Extra permissions checks
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
@@ -414,6 +423,14 @@ private:
status_t initializeShimMetadata(int cameraId);
/**
+ * Get the cached CameraParameters for the camera. If they haven't been
+ * cached yet, then initialize them for the first time.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ status_t getLegacyParametersLazy(int cameraId, /*out*/CameraParameters* parameters);
+
+ /**
* Generate the CameraCharacteristics metadata required by the Camera2 API
* from the available HAL1 CameraParameters and CameraInfo.
*