Merge change 22986 into eclair
* changes: Squashed commit of the following:
This commit is contained in:
@@ -38,23 +38,3 @@ LOCAL_CFLAGS += -Wno-multichar
|
|||||||
LOCAL_MODULE:= record
|
LOCAL_MODULE:= record
|
||||||
|
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
# include $(CLEAR_VARS)
|
|
||||||
#
|
|
||||||
# LOCAL_SRC_FILES:= \
|
|
||||||
# play.cpp
|
|
||||||
#
|
|
||||||
# LOCAL_SHARED_LIBRARIES := \
|
|
||||||
# libstagefright
|
|
||||||
#
|
|
||||||
# LOCAL_C_INCLUDES:= \
|
|
||||||
# frameworks/base/media/libstagefright \
|
|
||||||
# $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
|
|
||||||
#
|
|
||||||
# LOCAL_CFLAGS += -Wno-multichar
|
|
||||||
#
|
|
||||||
# LOCAL_MODULE:= play
|
|
||||||
#
|
|
||||||
# include $(BUILD_EXECUTABLE)
|
|
||||||
|
|||||||
@@ -1,295 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <binder/ProcessState.h>
|
|
||||||
#include <media/stagefright/OMXClient.h>
|
|
||||||
#include <media/stagefright/TimedEventQueue.h>
|
|
||||||
#include <media/stagefright/MPEG4Extractor.h>
|
|
||||||
#include <media/stagefright/MediaSource.h>
|
|
||||||
#include <media/stagefright/MetaData.h>
|
|
||||||
#include <media/stagefright/MmapSource.h>
|
|
||||||
#include <media/stagefright/OMXDecoder.h>
|
|
||||||
|
|
||||||
using namespace android;
|
|
||||||
|
|
||||||
struct NewPlayer {
|
|
||||||
NewPlayer();
|
|
||||||
~NewPlayer();
|
|
||||||
|
|
||||||
void setSource(const char *uri);
|
|
||||||
void start();
|
|
||||||
void pause();
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct PlayerEvent : public TimedEventQueue::Event {
|
|
||||||
PlayerEvent(NewPlayer *player,
|
|
||||||
void (NewPlayer::*method)(int64_t realtime_us))
|
|
||||||
: mPlayer(player),
|
|
||||||
mMethod(method) {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void fire(TimedEventQueue *queue, int64_t realtime_us) {
|
|
||||||
(mPlayer->*mMethod)(realtime_us);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
NewPlayer *mPlayer;
|
|
||||||
void (NewPlayer::*mMethod)(int64_t realtime_us);
|
|
||||||
|
|
||||||
PlayerEvent(const PlayerEvent &);
|
|
||||||
PlayerEvent &operator=(const PlayerEvent &);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PlayVideoFrameEvent : public TimedEventQueue::Event {
|
|
||||||
PlayVideoFrameEvent(NewPlayer *player, MediaBuffer *buffer)
|
|
||||||
: mPlayer(player),
|
|
||||||
mBuffer(buffer) {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~PlayVideoFrameEvent() {
|
|
||||||
if (mBuffer != NULL) {
|
|
||||||
mBuffer->release();
|
|
||||||
mBuffer = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void fire(TimedEventQueue *queue, int64_t realtime_us) {
|
|
||||||
mPlayer->onPlayVideoFrame(realtime_us, mBuffer);
|
|
||||||
mBuffer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
NewPlayer *mPlayer;
|
|
||||||
MediaBuffer *mBuffer;
|
|
||||||
|
|
||||||
PlayVideoFrameEvent(const PlayVideoFrameEvent &);
|
|
||||||
PlayVideoFrameEvent &operator=(const PlayVideoFrameEvent &);
|
|
||||||
};
|
|
||||||
|
|
||||||
OMXClient mClient;
|
|
||||||
|
|
||||||
MPEG4Extractor *mExtractor;
|
|
||||||
MediaSource *mAudioSource;
|
|
||||||
OMXDecoder *mAudioDecoder;
|
|
||||||
MediaSource *mVideoSource;
|
|
||||||
OMXDecoder *mVideoDecoder;
|
|
||||||
|
|
||||||
int32_t mVideoWidth, mVideoHeight;
|
|
||||||
|
|
||||||
TimedEventQueue mQueue;
|
|
||||||
wp<TimedEventQueue::Event> mPlayVideoFrameEvent;
|
|
||||||
|
|
||||||
int64_t mMediaTimeUsStart;
|
|
||||||
int64_t mRealTimeUsStart;
|
|
||||||
|
|
||||||
void setAudioSource(MediaSource *source);
|
|
||||||
void setVideoSource(MediaSource *source);
|
|
||||||
|
|
||||||
int64_t approxRealTime(int64_t mediatime_us) const;
|
|
||||||
|
|
||||||
void onStart(int64_t realtime_us);
|
|
||||||
void onPause(int64_t realtime_us);
|
|
||||||
void onFetchVideoFrame(int64_t realtime_us);
|
|
||||||
void onPlayVideoFrame(int64_t realtime_us, MediaBuffer *buffer);
|
|
||||||
|
|
||||||
static int64_t getMediaBufferTimeUs(MediaBuffer *buffer);
|
|
||||||
|
|
||||||
NewPlayer(const NewPlayer &);
|
|
||||||
NewPlayer &operator=(const NewPlayer &);
|
|
||||||
};
|
|
||||||
|
|
||||||
NewPlayer::NewPlayer()
|
|
||||||
: mExtractor(NULL),
|
|
||||||
mAudioSource(NULL),
|
|
||||||
mAudioDecoder(NULL),
|
|
||||||
mVideoSource(NULL),
|
|
||||||
mVideoDecoder(NULL),
|
|
||||||
mVideoWidth(0),
|
|
||||||
mVideoHeight(0) {
|
|
||||||
status_t err = mClient.connect();
|
|
||||||
assert(err == OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
NewPlayer::~NewPlayer() {
|
|
||||||
stop();
|
|
||||||
|
|
||||||
mClient.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NewPlayer::setSource(const char *uri) {
|
|
||||||
stop();
|
|
||||||
|
|
||||||
mExtractor = new MPEG4Extractor(new MmapSource(uri));
|
|
||||||
|
|
||||||
int num_tracks;
|
|
||||||
status_t err = mExtractor->countTracks(&num_tracks);
|
|
||||||
assert(err == OK);
|
|
||||||
|
|
||||||
for (int i = 0; i < num_tracks; ++i) {
|
|
||||||
const sp<MetaData> meta = mExtractor->getTrackMetaData(i);
|
|
||||||
assert(meta != NULL);
|
|
||||||
|
|
||||||
const char *mime;
|
|
||||||
if (!meta->findCString(kKeyMIMEType, &mime)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_audio = false;
|
|
||||||
bool is_acceptable = false;
|
|
||||||
if (!strncasecmp(mime, "audio/", 6)) {
|
|
||||||
is_audio = true;
|
|
||||||
is_acceptable = (mAudioSource == NULL);
|
|
||||||
} else if (!strncasecmp(mime, "video/", 6)) {
|
|
||||||
is_acceptable = (mVideoSource == NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_acceptable) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaSource *source;
|
|
||||||
if (mExtractor->getTrack(i, &source) != OK) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_audio) {
|
|
||||||
setAudioSource(source);
|
|
||||||
} else {
|
|
||||||
setVideoSource(source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NewPlayer::setAudioSource(MediaSource *source) {
|
|
||||||
mAudioSource = source;
|
|
||||||
|
|
||||||
sp<MetaData> meta = source->getFormat();
|
|
||||||
|
|
||||||
mAudioDecoder = OMXDecoder::Create(&mClient, meta);
|
|
||||||
mAudioDecoder->setSource(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NewPlayer::setVideoSource(MediaSource *source) {
|
|
||||||
mVideoSource = source;
|
|
||||||
|
|
||||||
sp<MetaData> meta = source->getFormat();
|
|
||||||
|
|
||||||
bool success = meta->findInt32(kKeyWidth, &mVideoWidth);
|
|
||||||
assert(success);
|
|
||||||
|
|
||||||
success = meta->findInt32(kKeyHeight, &mVideoHeight);
|
|
||||||
assert(success);
|
|
||||||
|
|
||||||
mVideoDecoder = OMXDecoder::Create(&mClient, meta);
|
|
||||||
mVideoDecoder->setSource(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NewPlayer::start() {
|
|
||||||
mQueue.start();
|
|
||||||
mQueue.postEvent(new PlayerEvent(this, &NewPlayer::onStart));
|
|
||||||
}
|
|
||||||
|
|
||||||
void NewPlayer::pause() {
|
|
||||||
mQueue.postEvent(new PlayerEvent(this, &NewPlayer::onPause));
|
|
||||||
}
|
|
||||||
|
|
||||||
void NewPlayer::stop() {
|
|
||||||
mQueue.stop();
|
|
||||||
|
|
||||||
delete mVideoDecoder;
|
|
||||||
mVideoDecoder = NULL;
|
|
||||||
delete mVideoSource;
|
|
||||||
mVideoSource = NULL;
|
|
||||||
mVideoWidth = mVideoHeight = 0;
|
|
||||||
|
|
||||||
delete mAudioDecoder;
|
|
||||||
mAudioDecoder = NULL;
|
|
||||||
delete mAudioSource;
|
|
||||||
mAudioSource = NULL;
|
|
||||||
|
|
||||||
delete mExtractor;
|
|
||||||
mExtractor = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t NewPlayer::approxRealTime(int64_t mediatime_us) const {
|
|
||||||
return mRealTimeUsStart + (mediatime_us - mMediaTimeUsStart);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NewPlayer::onStart(int64_t realtime_us) {
|
|
||||||
mRealTimeUsStart = TimedEventQueue::getRealTimeUs();
|
|
||||||
|
|
||||||
if (mVideoDecoder != NULL) {
|
|
||||||
mQueue.postEvent(new PlayerEvent(this, &NewPlayer::onFetchVideoFrame));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NewPlayer::onFetchVideoFrame(int64_t realtime_us) {
|
|
||||||
MediaBuffer *buffer;
|
|
||||||
status_t err = mVideoDecoder->read(&buffer);
|
|
||||||
assert(err == OK);
|
|
||||||
|
|
||||||
int64_t mediatime_us = getMediaBufferTimeUs(buffer);
|
|
||||||
|
|
||||||
sp<TimedEventQueue::Event> event = new PlayVideoFrameEvent(this, buffer);
|
|
||||||
mPlayVideoFrameEvent = event;
|
|
||||||
|
|
||||||
mQueue.postTimedEvent(event, approxRealTime(mediatime_us));
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
int64_t NewPlayer::getMediaBufferTimeUs(MediaBuffer *buffer) {
|
|
||||||
int32_t units, scale;
|
|
||||||
bool success =
|
|
||||||
buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
|
|
||||||
assert(success);
|
|
||||||
success =
|
|
||||||
buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
|
|
||||||
assert(success);
|
|
||||||
|
|
||||||
return (int64_t)units * 1000000 / scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NewPlayer::onPlayVideoFrame(int64_t realtime_us, MediaBuffer *buffer) {
|
|
||||||
LOGI("playing video frame (mediatime: %.2f sec)\n",
|
|
||||||
getMediaBufferTimeUs(buffer) / 1E6);
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
buffer->release();
|
|
||||||
buffer = NULL;
|
|
||||||
|
|
||||||
mQueue.postEvent(new PlayerEvent(this, &NewPlayer::onFetchVideoFrame));
|
|
||||||
}
|
|
||||||
|
|
||||||
void NewPlayer::onPause(int64_t realtime_us) {
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
android::ProcessState::self()->startThreadPool();
|
|
||||||
|
|
||||||
if (argc != 2) {
|
|
||||||
fprintf(stderr, "usage: %s filename\n", argv[0]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
NewPlayer player;
|
|
||||||
player.setSource(argv[1]);
|
|
||||||
player.start();
|
|
||||||
sleep(10);
|
|
||||||
player.stop();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -26,7 +26,6 @@
|
|||||||
#include <media/stagefright/MmapSource.h>
|
#include <media/stagefright/MmapSource.h>
|
||||||
#include <media/stagefright/OMXClient.h>
|
#include <media/stagefright/OMXClient.h>
|
||||||
#include <media/stagefright/OMXCodec.h>
|
#include <media/stagefright/OMXCodec.h>
|
||||||
#include <media/stagefright/OMXDecoder.h>
|
|
||||||
|
|
||||||
using namespace android;
|
using namespace android;
|
||||||
|
|
||||||
@@ -87,8 +86,6 @@ private:
|
|||||||
DummySource &operator=(const DummySource &);
|
DummySource &operator=(const DummySource &);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define USE_OMX_CODEC 1
|
|
||||||
|
|
||||||
sp<MediaSource> createSource(const char *filename) {
|
sp<MediaSource> createSource(const char *filename) {
|
||||||
sp<MediaSource> source;
|
sp<MediaSource> source;
|
||||||
|
|
||||||
@@ -140,13 +137,8 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
sp<MetaData> meta = source->getFormat();
|
sp<MetaData> meta = source->getFormat();
|
||||||
|
|
||||||
#if USE_OMX_CODEC
|
|
||||||
sp<OMXCodec> decoder = OMXCodec::Create(
|
sp<OMXCodec> decoder = OMXCodec::Create(
|
||||||
client.interface(), meta, false /* createEncoder */, source);
|
client.interface(), meta, false /* createEncoder */, source);
|
||||||
#else
|
|
||||||
sp<OMXDecoder> decoder = OMXDecoder::Create(
|
|
||||||
&client, meta, false /* createEncoder */, source);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int width, height;
|
int width, height;
|
||||||
bool success = meta->findInt32(kKeyWidth, &width);
|
bool success = meta->findInt32(kKeyWidth, &width);
|
||||||
@@ -164,14 +156,9 @@ int main(int argc, char **argv) {
|
|||||||
enc_meta->setInt32(kKeyWidth, width);
|
enc_meta->setInt32(kKeyWidth, width);
|
||||||
enc_meta->setInt32(kKeyHeight, height);
|
enc_meta->setInt32(kKeyHeight, height);
|
||||||
|
|
||||||
#if USE_OMX_CODEC
|
|
||||||
sp<OMXCodec> encoder =
|
sp<OMXCodec> encoder =
|
||||||
OMXCodec::Create(
|
OMXCodec::Create(
|
||||||
client.interface(), enc_meta, true /* createEncoder */, decoder);
|
client.interface(), enc_meta, true /* createEncoder */, decoder);
|
||||||
#else
|
|
||||||
sp<OMXDecoder> encoder = OMXDecoder::Create(
|
|
||||||
&client, enc_meta, true /* createEncoder */, decoder);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
|
sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
|
||||||
|
|||||||
@@ -33,7 +33,6 @@
|
|||||||
#include <media/stagefright/MmapSource.h>
|
#include <media/stagefright/MmapSource.h>
|
||||||
#include <media/stagefright/OMXClient.h>
|
#include <media/stagefright/OMXClient.h>
|
||||||
#include <media/stagefright/OMXCodec.h>
|
#include <media/stagefright/OMXCodec.h>
|
||||||
#include <media/stagefright/OMXDecoder.h>
|
|
||||||
|
|
||||||
#include "JPEGSource.h"
|
#include "JPEGSource.h"
|
||||||
|
|
||||||
@@ -50,18 +49,11 @@ static int64_t getNowUs() {
|
|||||||
return (int64_t)tv.tv_usec + tv.tv_sec * 1000000;
|
return (int64_t)tv.tv_usec + tv.tv_sec * 1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define USE_OMX_CODEC 1
|
|
||||||
|
|
||||||
static void playSource(OMXClient *client, const sp<MediaSource> &source) {
|
static void playSource(OMXClient *client, const sp<MediaSource> &source) {
|
||||||
sp<MetaData> meta = source->getFormat();
|
sp<MetaData> meta = source->getFormat();
|
||||||
|
|
||||||
#if !USE_OMX_CODEC
|
|
||||||
sp<OMXDecoder> decoder = OMXDecoder::Create(
|
|
||||||
client, meta, false /* createEncoder */, source);
|
|
||||||
#else
|
|
||||||
sp<OMXCodec> decoder = OMXCodec::Create(
|
sp<OMXCodec> decoder = OMXCodec::Create(
|
||||||
client->interface(), meta, false /* createEncoder */, source);
|
client->interface(), meta, false /* createEncoder */, source);
|
||||||
#endif
|
|
||||||
|
|
||||||
if (decoder == NULL) {
|
if (decoder == NULL) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -119,12 +119,6 @@ struct omx_message {
|
|||||||
EMPTY_BUFFER_DONE,
|
EMPTY_BUFFER_DONE,
|
||||||
FILL_BUFFER_DONE,
|
FILL_BUFFER_DONE,
|
||||||
|
|
||||||
// reserved for OMXDecoder use.
|
|
||||||
START,
|
|
||||||
INITIAL_FILL_BUFFER,
|
|
||||||
|
|
||||||
// reserved for OMXObserver use.
|
|
||||||
QUIT_OBSERVER,
|
|
||||||
} type;
|
} type;
|
||||||
|
|
||||||
IOMX::node_id node;
|
IOMX::node_id node;
|
||||||
@@ -137,28 +131,21 @@ struct omx_message {
|
|||||||
OMX_U32 data2;
|
OMX_U32 data2;
|
||||||
} event_data;
|
} event_data;
|
||||||
|
|
||||||
// if type == EMPTY_BUFFER_DONE || type == FILL_BUFFER
|
// if type == EMPTY_BUFFER_DONE
|
||||||
// || type == INITIAL_FILL_BUFFER
|
|
||||||
struct {
|
struct {
|
||||||
IOMX::buffer_id buffer;
|
IOMX::buffer_id buffer;
|
||||||
} buffer_data;
|
} buffer_data;
|
||||||
|
|
||||||
// if type == EMPTY_BUFFER || type == FILL_BUFFER_DONE
|
// if type == FILL_BUFFER_DONE
|
||||||
struct {
|
struct {
|
||||||
IOMX::buffer_id buffer;
|
IOMX::buffer_id buffer;
|
||||||
OMX_U32 range_offset;
|
OMX_U32 range_offset;
|
||||||
OMX_U32 range_length;
|
OMX_U32 range_length;
|
||||||
OMX_U32 flags;
|
OMX_U32 flags;
|
||||||
OMX_TICKS timestamp;
|
OMX_TICKS timestamp;
|
||||||
OMX_PTR platform_private; // ignored if type == EMPTY_BUFFER
|
OMX_PTR platform_private;
|
||||||
} extended_buffer_data;
|
} extended_buffer_data;
|
||||||
|
|
||||||
// if type == SEND_COMMAND
|
|
||||||
struct {
|
|
||||||
OMX_COMMANDTYPE cmd;
|
|
||||||
OMX_S32 param;
|
|
||||||
} send_command_data;
|
|
||||||
|
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,62 +20,11 @@
|
|||||||
|
|
||||||
#include <media/IOMX.h>
|
#include <media/IOMX.h>
|
||||||
|
|
||||||
#include <utils/KeyedVector.h>
|
|
||||||
#include <utils/List.h>
|
|
||||||
#include <utils/threads.h>
|
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
class OMXObserver {
|
|
||||||
public:
|
|
||||||
OMXObserver();
|
|
||||||
virtual ~OMXObserver();
|
|
||||||
|
|
||||||
void postMessage(const omx_message &msg);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void onOMXMessage(const omx_message &msg) = 0;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class OMXClient;
|
|
||||||
|
|
||||||
pthread_t mThread;
|
|
||||||
Mutex mLock;
|
|
||||||
Condition mQueueNotEmpty;
|
|
||||||
List<omx_message> mQueue;
|
|
||||||
|
|
||||||
void start();
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
static void *ThreadWrapper(void *me);
|
|
||||||
void threadEntry();
|
|
||||||
|
|
||||||
OMXObserver(const OMXObserver &);
|
|
||||||
OMXObserver &operator=(const OMXObserver &);
|
|
||||||
};
|
|
||||||
|
|
||||||
class OMXClient;
|
|
||||||
|
|
||||||
class OMXClientReflector : public BnOMXObserver {
|
|
||||||
public:
|
|
||||||
OMXClientReflector(OMXClient *client);
|
|
||||||
|
|
||||||
virtual void on_message(const omx_message &msg);
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
private:
|
|
||||||
OMXClient *mClient;
|
|
||||||
|
|
||||||
OMXClientReflector(const OMXClientReflector &);
|
|
||||||
OMXClientReflector &operator=(const OMXClientReflector &);
|
|
||||||
};
|
|
||||||
|
|
||||||
class OMXClient {
|
class OMXClient {
|
||||||
public:
|
public:
|
||||||
friend class OMXClientReflector;
|
|
||||||
|
|
||||||
OMXClient();
|
OMXClient();
|
||||||
~OMXClient();
|
|
||||||
|
|
||||||
status_t connect();
|
status_t connect();
|
||||||
void disconnect();
|
void disconnect();
|
||||||
@@ -84,18 +33,8 @@ public:
|
|||||||
return mOMX;
|
return mOMX;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t registerObserver(IOMX::node_id node, OMXObserver *observer);
|
|
||||||
void unregisterObserver(IOMX::node_id node);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sp<IOMX> mOMX;
|
sp<IOMX> mOMX;
|
||||||
Mutex mLock;
|
|
||||||
|
|
||||||
KeyedVector<IOMX::node_id, OMXObserver *> mObservers;
|
|
||||||
|
|
||||||
sp<OMXClientReflector> mReflector;
|
|
||||||
|
|
||||||
bool onOMXMessage(const omx_message &msg);
|
|
||||||
|
|
||||||
OMXClient(const OMXClient &);
|
OMXClient(const OMXClient &);
|
||||||
OMXClient &operator=(const OMXClient &);
|
OMXClient &operator=(const OMXClient &);
|
||||||
|
|||||||
@@ -1,185 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 OMX_DECODER_H_
|
|
||||||
|
|
||||||
#define OMX_DECODER_H_
|
|
||||||
|
|
||||||
#include <binder/MemoryDealer.h>
|
|
||||||
#include <media/stagefright/MediaBuffer.h>
|
|
||||||
#include <media/stagefright/MediaSource.h>
|
|
||||||
#include <media/stagefright/OMXClient.h>
|
|
||||||
#include <utils/KeyedVector.h>
|
|
||||||
#include <utils/List.h>
|
|
||||||
#include <utils/threads.h>
|
|
||||||
|
|
||||||
#include <OMX_Video.h>
|
|
||||||
|
|
||||||
namespace android {
|
|
||||||
|
|
||||||
class OMXMediaBuffer;
|
|
||||||
|
|
||||||
class OMXDecoder : public MediaSource,
|
|
||||||
public OMXObserver,
|
|
||||||
public MediaBufferObserver {
|
|
||||||
public:
|
|
||||||
static sp<OMXDecoder> Create(
|
|
||||||
OMXClient *client, const sp<MetaData> &data,
|
|
||||||
bool createEncoder,
|
|
||||||
const sp<MediaSource> &source);
|
|
||||||
|
|
||||||
virtual status_t start(MetaData *params = NULL);
|
|
||||||
virtual status_t stop();
|
|
||||||
|
|
||||||
virtual sp<MetaData> getFormat();
|
|
||||||
|
|
||||||
virtual status_t read(
|
|
||||||
MediaBuffer **buffer, const ReadOptions *options = NULL);
|
|
||||||
|
|
||||||
void addCodecSpecificData(const void *data, size_t size);
|
|
||||||
|
|
||||||
// from OMXObserver
|
|
||||||
virtual void onOMXMessage(const omx_message &msg);
|
|
||||||
|
|
||||||
// from MediaBufferObserver
|
|
||||||
virtual void signalBufferReturned(MediaBuffer *buffer);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual ~OMXDecoder();
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum {
|
|
||||||
kPortIndexInput = 0,
|
|
||||||
kPortIndexOutput = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum PortStatus {
|
|
||||||
kPortStatusActive = 0,
|
|
||||||
kPortStatusDisabled = 1,
|
|
||||||
kPortStatusShutdown = 2,
|
|
||||||
kPortStatusFlushing = 3,
|
|
||||||
kPortStatusFlushingToDisabled = 4,
|
|
||||||
kPortStatusFlushingToShutdown = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Quirks {
|
|
||||||
kWantsNALFragments = 1,
|
|
||||||
kDoesntReturnBuffersOnDisable = 2,
|
|
||||||
kDoesntFlushOnExecutingToIdle = 4,
|
|
||||||
kDoesntProperlyFlushAllPortsAtOnce = 8,
|
|
||||||
kRequiresAllocateBufferOnInputPorts = 16,
|
|
||||||
kRequiresAllocateBufferOnOutputPorts = 32,
|
|
||||||
kRequiresLoadedToIdleAfterAllocation = 64,
|
|
||||||
kMeasuresTimeInMilliseconds = 128,
|
|
||||||
};
|
|
||||||
|
|
||||||
OMXClient *mClient;
|
|
||||||
sp<IOMX> mOMX;
|
|
||||||
IOMX::node_id mNode;
|
|
||||||
char *mComponentName;
|
|
||||||
char *mMIME;
|
|
||||||
bool mIsMP3;
|
|
||||||
bool mIsAVC;
|
|
||||||
bool mIsEncoder;
|
|
||||||
uint32_t mQuirks;
|
|
||||||
|
|
||||||
sp<MediaSource> mSource;
|
|
||||||
sp<MetaData> mOutputFormat;
|
|
||||||
|
|
||||||
Mutex mLock;
|
|
||||||
Condition mOutputBufferAvailable;
|
|
||||||
|
|
||||||
List<MediaBuffer *> mOutputBuffers;
|
|
||||||
|
|
||||||
struct CodecSpecificData {
|
|
||||||
void *data;
|
|
||||||
size_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
List<CodecSpecificData> mCodecSpecificData;
|
|
||||||
List<CodecSpecificData>::iterator mCodecSpecificDataIterator;
|
|
||||||
|
|
||||||
volatile OMX_STATETYPE mState;
|
|
||||||
OMX_U32 mPortStatusMask;
|
|
||||||
bool mShutdownInitiated;
|
|
||||||
|
|
||||||
typedef List<IOMX::buffer_id> BufferList;
|
|
||||||
Vector<BufferList> mBuffers;
|
|
||||||
|
|
||||||
KeyedVector<IOMX::buffer_id, sp<IMemory> > mBufferMap;
|
|
||||||
KeyedVector<IOMX::buffer_id, OMXMediaBuffer *> mMediaBufferMap;
|
|
||||||
|
|
||||||
sp<MemoryDealer> mDealer;
|
|
||||||
|
|
||||||
bool mSeeking;
|
|
||||||
int64_t mSeekTimeUs;
|
|
||||||
|
|
||||||
bool mStarted;
|
|
||||||
status_t mErrorCondition;
|
|
||||||
bool mReachedEndOfInput;
|
|
||||||
|
|
||||||
OMXDecoder(OMXClient *client, IOMX::node_id node,
|
|
||||||
const char *mime, const char *codec,
|
|
||||||
bool is_encoder,
|
|
||||||
uint32_t quirks,
|
|
||||||
const sp<MediaSource> &source);
|
|
||||||
|
|
||||||
void setPortStatus(OMX_U32 port_index, PortStatus status);
|
|
||||||
PortStatus getPortStatus(OMX_U32 port_index) const;
|
|
||||||
|
|
||||||
void allocateBuffers(OMX_U32 port_index);
|
|
||||||
|
|
||||||
void setAMRFormat();
|
|
||||||
void setAACFormat();
|
|
||||||
|
|
||||||
status_t setVideoPortFormatType(
|
|
||||||
OMX_U32 portIndex,
|
|
||||||
OMX_VIDEO_CODINGTYPE compressionFormat,
|
|
||||||
OMX_COLOR_FORMATTYPE colorFormat);
|
|
||||||
|
|
||||||
void setVideoOutputFormat(const char *mime, OMX_U32 width, OMX_U32 height);
|
|
||||||
void setVideoInputFormat(const char *mime, OMX_U32 width, OMX_U32 height);
|
|
||||||
void setup();
|
|
||||||
void dumpPortDefinition(OMX_U32 port_index);
|
|
||||||
|
|
||||||
void onStart();
|
|
||||||
void onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
|
|
||||||
void onEventCmdComplete(OMX_COMMANDTYPE type, OMX_U32 data);
|
|
||||||
void onEventPortSettingsChanged(OMX_U32 port_index);
|
|
||||||
void onStateChanged(OMX_STATETYPE to);
|
|
||||||
void onEmptyBufferDone(IOMX::buffer_id buffer);
|
|
||||||
void onFillBufferDone(const omx_message &msg);
|
|
||||||
|
|
||||||
void onRealEmptyBufferDone(IOMX::buffer_id buffer);
|
|
||||||
void onRealFillBufferDone(const omx_message &msg);
|
|
||||||
|
|
||||||
void initiateShutdown();
|
|
||||||
|
|
||||||
void freeInputBuffer(IOMX::buffer_id buffer);
|
|
||||||
void freeOutputBuffer(IOMX::buffer_id buffer);
|
|
||||||
void freePortBuffers(OMX_U32 port_index);
|
|
||||||
|
|
||||||
void postStart();
|
|
||||||
void postEmptyBufferDone(IOMX::buffer_id buffer);
|
|
||||||
void postInitialFillBuffer(IOMX::buffer_id buffer);
|
|
||||||
|
|
||||||
OMXDecoder(const OMXDecoder &);
|
|
||||||
OMXDecoder &operator=(const OMXDecoder &);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace android
|
|
||||||
|
|
||||||
#endif // OMX_DECODER_H_
|
|
||||||
@@ -26,7 +26,6 @@ LOCAL_SRC_FILES:= \
|
|||||||
AudioPlayer.cpp \
|
AudioPlayer.cpp \
|
||||||
ESDS.cpp \
|
ESDS.cpp \
|
||||||
OMXClient.cpp \
|
OMXClient.cpp \
|
||||||
OMXDecoder.cpp \
|
|
||||||
string.cpp
|
string.cpp
|
||||||
|
|
||||||
LOCAL_C_INCLUDES:= \
|
LOCAL_C_INCLUDES:= \
|
||||||
|
|||||||
@@ -33,14 +33,11 @@
|
|||||||
#include <media/stagefright/MetaData.h>
|
#include <media/stagefright/MetaData.h>
|
||||||
#include <media/stagefright/MmapSource.h>
|
#include <media/stagefright/MmapSource.h>
|
||||||
#include <media/stagefright/OMXCodec.h>
|
#include <media/stagefright/OMXCodec.h>
|
||||||
#include <media/stagefright/OMXDecoder.h>
|
|
||||||
#include <media/stagefright/ShoutcastSource.h>
|
#include <media/stagefright/ShoutcastSource.h>
|
||||||
#include <media/stagefright/TimeSource.h>
|
#include <media/stagefright/TimeSource.h>
|
||||||
#include <ui/PixelFormat.h>
|
#include <ui/PixelFormat.h>
|
||||||
#include <ui/Surface.h>
|
#include <ui/Surface.h>
|
||||||
|
|
||||||
#define USE_OMX_CODEC 1
|
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
MediaPlayerImpl::MediaPlayerImpl(const char *uri)
|
MediaPlayerImpl::MediaPlayerImpl(const char *uri)
|
||||||
@@ -406,13 +403,8 @@ void MediaPlayerImpl::setAudioSource(const sp<MediaSource> &source) {
|
|||||||
|
|
||||||
sp<MetaData> meta = source->getFormat();
|
sp<MetaData> meta = source->getFormat();
|
||||||
|
|
||||||
#if !USE_OMX_CODEC
|
|
||||||
mAudioDecoder = OMXDecoder::Create(
|
|
||||||
&mClient, meta, false /* createEncoder */, source);
|
|
||||||
#else
|
|
||||||
mAudioDecoder = OMXCodec::Create(
|
mAudioDecoder = OMXCodec::Create(
|
||||||
mClient.interface(), meta, false /* createEncoder */, source);
|
mClient.interface(), meta, false /* createEncoder */, source);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaPlayerImpl::setVideoSource(const sp<MediaSource> &source) {
|
void MediaPlayerImpl::setVideoSource(const sp<MediaSource> &source) {
|
||||||
@@ -427,13 +419,8 @@ void MediaPlayerImpl::setVideoSource(const sp<MediaSource> &source) {
|
|||||||
success = meta->findInt32(kKeyHeight, &mVideoHeight);
|
success = meta->findInt32(kKeyHeight, &mVideoHeight);
|
||||||
CHECK(success);
|
CHECK(success);
|
||||||
|
|
||||||
#if !USE_OMX_CODEC
|
|
||||||
mVideoDecoder = OMXDecoder::Create(
|
|
||||||
&mClient, meta, false /* createEncoder */, source);
|
|
||||||
#else
|
|
||||||
mVideoDecoder = OMXCodec::Create(
|
mVideoDecoder = OMXCodec::Create(
|
||||||
mClient.interface(), meta, false /* createEncoder */, source);
|
mClient.interface(), meta, false /* createEncoder */, source);
|
||||||
#endif
|
|
||||||
|
|
||||||
if (mISurface.get() != NULL || mSurface.get() != NULL) {
|
if (mISurface.get() != NULL || mSurface.get() != NULL) {
|
||||||
depopulateISurface();
|
depopulateISurface();
|
||||||
|
|||||||
@@ -18,11 +18,8 @@
|
|||||||
#define LOG_TAG "OMXClient"
|
#define LOG_TAG "OMXClient"
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
|
|
||||||
#include <sys/socket.h>
|
|
||||||
|
|
||||||
#include <binder/IServiceManager.h>
|
#include <binder/IServiceManager.h>
|
||||||
#include <media/IMediaPlayerService.h>
|
#include <media/IMediaPlayerService.h>
|
||||||
#include <media/IOMX.h>
|
|
||||||
#include <media/stagefright/MediaDebug.h>
|
#include <media/stagefright/MediaDebug.h>
|
||||||
#include <media/stagefright/OMXClient.h>
|
#include <media/stagefright/OMXClient.h>
|
||||||
|
|
||||||
@@ -31,13 +28,7 @@ namespace android {
|
|||||||
OMXClient::OMXClient() {
|
OMXClient::OMXClient() {
|
||||||
}
|
}
|
||||||
|
|
||||||
OMXClient::~OMXClient() {
|
|
||||||
disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
status_t OMXClient::connect() {
|
status_t OMXClient::connect() {
|
||||||
Mutex::Autolock autoLock(mLock);
|
|
||||||
|
|
||||||
sp<IServiceManager> sm = defaultServiceManager();
|
sp<IServiceManager> sm = defaultServiceManager();
|
||||||
sp<IBinder> binder = sm->getService(String16("media.player"));
|
sp<IBinder> binder = sm->getService(String16("media.player"));
|
||||||
sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
|
sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
|
||||||
@@ -47,175 +38,10 @@ status_t OMXClient::connect() {
|
|||||||
mOMX = service->createOMX();
|
mOMX = service->createOMX();
|
||||||
CHECK(mOMX.get() != NULL);
|
CHECK(mOMX.get() != NULL);
|
||||||
|
|
||||||
mReflector = new OMXClientReflector(this);
|
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OMXClient::disconnect() {
|
void OMXClient::disconnect() {
|
||||||
Mutex::Autolock autoLock(mLock);
|
|
||||||
|
|
||||||
if (mReflector.get() != NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECK(mObservers.isEmpty());
|
|
||||||
|
|
||||||
mReflector->reset();
|
|
||||||
mReflector.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
status_t OMXClient::registerObserver(
|
|
||||||
IOMX::node_id node, OMXObserver *observer) {
|
|
||||||
Mutex::Autolock autoLock(&mLock);
|
|
||||||
|
|
||||||
ssize_t index = mObservers.indexOfKey(node);
|
|
||||||
if (index >= 0) {
|
|
||||||
return UNKNOWN_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
mObservers.add(node, observer);
|
|
||||||
observer->start();
|
|
||||||
|
|
||||||
mOMX->observe_node(node, mReflector);
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OMXClient::unregisterObserver(IOMX::node_id node) {
|
|
||||||
Mutex::Autolock autoLock(mLock);
|
|
||||||
|
|
||||||
ssize_t index = mObservers.indexOfKey(node);
|
|
||||||
CHECK(index >= 0);
|
|
||||||
|
|
||||||
if (index < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OMXObserver *observer = mObservers.valueAt(index);
|
|
||||||
observer->stop();
|
|
||||||
mObservers.removeItemsAt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OMXClient::onOMXMessage(const omx_message &msg) {
|
|
||||||
bool done = false;
|
|
||||||
|
|
||||||
switch (msg.type) {
|
|
||||||
case omx_message::EVENT:
|
|
||||||
{
|
|
||||||
LOGV("OnEvent node:%p event:%d data1:%ld data2:%ld",
|
|
||||||
msg.u.event_data.node,
|
|
||||||
msg.u.event_data.event,
|
|
||||||
msg.u.event_data.data1,
|
|
||||||
msg.u.event_data.data2);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case omx_message::FILL_BUFFER_DONE:
|
|
||||||
{
|
|
||||||
LOGV("FillBufferDone %p", msg.u.extended_buffer_data.buffer);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case omx_message::EMPTY_BUFFER_DONE:
|
|
||||||
{
|
|
||||||
LOGV("EmptyBufferDone %p", msg.u.buffer_data.buffer);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
LOGE("received unknown omx_message type %d", msg.type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mutex::Autolock autoLock(mLock);
|
|
||||||
ssize_t index = mObservers.indexOfKey(msg.node);
|
|
||||||
|
|
||||||
if (index >= 0) {
|
|
||||||
mObservers.editValueAt(index)->postMessage(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
return done;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
OMXObserver::OMXObserver() {
|
|
||||||
}
|
|
||||||
|
|
||||||
OMXObserver::~OMXObserver() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void OMXObserver::start() {
|
|
||||||
pthread_attr_t attr;
|
|
||||||
pthread_attr_init(&attr);
|
|
||||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
|
||||||
|
|
||||||
int err = pthread_create(&mThread, &attr, ThreadWrapper, this);
|
|
||||||
CHECK_EQ(err, 0);
|
|
||||||
|
|
||||||
pthread_attr_destroy(&attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OMXObserver::stop() {
|
|
||||||
omx_message msg;
|
|
||||||
msg.type = omx_message::QUIT_OBSERVER;
|
|
||||||
postMessage(msg);
|
|
||||||
|
|
||||||
void *dummy;
|
|
||||||
pthread_join(mThread, &dummy);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OMXObserver::postMessage(const omx_message &msg) {
|
|
||||||
Mutex::Autolock autoLock(mLock);
|
|
||||||
mQueue.push_back(msg);
|
|
||||||
mQueueNotEmpty.signal();
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
void *OMXObserver::ThreadWrapper(void *me) {
|
|
||||||
static_cast<OMXObserver *>(me)->threadEntry();
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OMXObserver::threadEntry() {
|
|
||||||
for (;;) {
|
|
||||||
omx_message msg;
|
|
||||||
|
|
||||||
{
|
|
||||||
Mutex::Autolock autoLock(mLock);
|
|
||||||
while (mQueue.empty()) {
|
|
||||||
mQueueNotEmpty.wait(mLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = *mQueue.begin();
|
|
||||||
mQueue.erase(mQueue.begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg.type == omx_message::QUIT_OBSERVER) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
onOMXMessage(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
OMXClientReflector::OMXClientReflector(OMXClient *client)
|
|
||||||
: mClient(client) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void OMXClientReflector::on_message(const omx_message &msg) {
|
|
||||||
if (mClient != NULL) {
|
|
||||||
mClient->onOMXMessage(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OMXClientReflector::reset() {
|
|
||||||
mClient = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user