Introducing 

Prezi AI.

Your new presentation assistant.

Refine, enhance, and tailor your content, source relevant images, and edit visuals quicker than ever before.

Loading…
Transcript

Emulator for

Debugging

Overview

Media Player : Gingerbread Stagefright

Header Path : framework/base/include/media/stagefright

Source Path : framework/base/media/stagefright

Protocol : HTTP

File Format : MP4

To use Valgrind

AudioPlayer &

VideoRenderer

VideoRenderer.h

AudioPlayer.h

class VideoRenderer {

public:

virtual ~VideoRenderer() {}

virtual void render(

const void *data, size_t size, void *platformPrivate) = 0;

protected:

VideoRenderer() {}

VideoRenderer(const VideoRenderer &);

VideoRenderer &operator=(const VideoRenderer &);

};

8th Kandroid Conference

class AudioPlayer : public TimeSource {

public:

enum {

REACHED_EOS,

SEEK_COMPLETE

};

AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink,

AwesomePlayer *audioObserver = NULL);

virtual ~AudioPlayer();

// Caller retains ownership of "source".

void setSource(const sp<MediaSource> &source);

// Return time in us.

virtual int64_t getRealTimeUs();

status_t start(bool sourceAlreadyStarted = false);

void pause(bool playPendingSamples = false);

void resume();

// Returns the timestamp of the last buffer played (in us).

int64_t getMediaTimeUs();

status_t seekTo(int64_t time_us);

bool isSeeking();

bool reachedEOS(status_t *finalStatus);

Wrap Up

Stagefright

Inside of Stagefright

  • Honeycomb & ICS Stagefright
  • Q & A

Data Flow

Class Diagram

OMXCodec

OMXCodec.h

How to play HTTP streaming in Stagefright

HardwareAPI.h

struct OMXCodec : public MediaSource, public MediaBufferObserver {

enum CreationFlags {

kPreferSoftwareCodecs = 1,

kIgnoreCodecSpecificData = 2,

// The client wants to access the output buffer's video

// data for example for thumbnail extraction.

kClientNeedsFramebuffer = 4,

};

static sp<MediaSource> Create(

const sp<IOMX> &omx,

const sp<MetaData> &meta, bool createEncoder,

const sp<MediaSource> &source,

const char *matchComponentName = NULL,

uint32_t flags = 0);

....

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);

virtual status_t pause();

// from MediaBufferObserver

virtual void signalBufferReturned(MediaBuffer *buffer);

....

extern android::VideoRenderer *createRenderer(

const android::sp<android::ISurface> &surface,

const char *componentName,

OMX_COLOR_FORMATTYPE colorFormat,

size_t displayWidth, size_t displayHeight,

size_t decodedWidth, size_t decodedHeight);

extern android::VideoRenderer *createRendererWithRotation(

const android::sp<android::ISurface> &surface,

const char *componentName,

OMX_COLOR_FORMATTYPE colorFormat,

size_t displayWidth, size_t displayHeight,

size_t decodedWidth, size_t decodedHeight,

int32_t rotationDegrees);

extern android::OMXPluginBase *createOMXPlugin();

October 17,2011

jeonghoe.kim@windriver.com

private:

void onVideoEvent();

void onBufferingUpdate();

void onCheckAudioStatus();

AwesomePlayer

bool isPlaying() const;

void setISurface(const sp<ISurface> &isurface);

void setAudioSink(const sp<MediaPlayerBase::AudioSink> &audioSink);

status_t setLooping(bool shouldLoop);

status_t getDuration(int64_t *durationUs);

status_t getPosition(int64_t *positionUs);

status_t seekTo(int64_t timeUs);

status_t getVideoDimensions(int32_t *width, int32_t *height) const;

status_t suspend();

status_t resume();

// This is a mask of MediaExtractor::Flags.

uint32_t flags() const;

void postAudioEOS();

void postAudioSeekComplete();

AwesomePlayer.h

MediaExtractor

MediaExtractor.cpp

struct AwesomePlayer {

AwesomePlayer();

~AwesomePlayer();

void setListener(const wp<MediaPlayerBase> &listener);

status_t setDataSource(

const char *uri,

const KeyedVector<String8, String8> *headers = NULL);

status_t setDataSource(int fd, int64_t offset, int64_t length);

void reset();

status_t prepare();

status_t prepare_l();

status_t prepareAsync();

status_t prepareAsync_l();

status_t play();

status_t pause();

sp<MediaExtractor> MediaExtractor::Create(const sp<DataSource> &source, const char *mime) {

sp<AMessage> meta;

String8 tmp;

if (mime == NULL) {

float confidence;

if (!source->sniff(&tmp, &confidence, &meta)) {

LOGV("FAILED to autodetect media content.");

return NULL;

}

mime = tmp.string();

LOGV("Autodetected media content as '%s' with confidence %.2f", mime, confidence);

}

if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)

|| !strcasecmp(mime, "audio/mp4")) {

return new MPEG4Extractor(source);

} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {

return new MP3Extractor(source, meta);

} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)

|| !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {

return new AMRExtractor(source);

} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {

return new WAVExtractor(source);

} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {

return new OggExtractor(source);

} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {

return new MatroskaExtractor(source);

} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {

return new MPEG2TSExtractor(source);

}

return NULL;

}

MediaSource

MediaExtractor.h

MediaSource.h

class MediaExtractor : public RefBase {

public:

static sp<MediaExtractor> Create(

const sp<DataSource> &source, const char *mime = NULL);

virtual size_t countTracks() = 0;

virtual sp<MediaSource> getTrack(size_t index) = 0;

enum GetTrackMetaDataFlags {

kIncludeExtensiveMetaData = 1

};

virtual sp<MetaData> getTrackMetaData(

size_t index, uint32_t flags = 0) = 0;

.....

enum Flags {

CAN_SEEK_BACKWARD = 1, // the "seek 10secs back button"

CAN_SEEK_FORWARD = 2, // the "seek 10secs forward button"

CAN_PAUSE = 4,

CAN_SEEK = 8, // the "seek bar"

};

// If subclasses do _not_ override this, the default is

// CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE

virtual uint32_t flags() const;

......

};

// Options that modify read() behaviour. The default is to

// a) not request a seek

// b) not be late, i.e. lateness_us = 0

struct ReadOptions {

enum SeekMode {

SEEK_PREVIOUS_SYNC,

SEEK_NEXT_SYNC,

SEEK_CLOSEST_SYNC,

SEEK_CLOSEST,

};

ReadOptions();

// Reset everything back to defaults.

void reset();

void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC);

void clearSeekTo();

bool getSeekTo(int64_t *time_us, SeekMode *mode) const;

// Option allows encoder to skip some frames until the specified

// time stamp.

// To prevent from being abused, when the skipFrame timestamp is

// found to be more than 1 second later than the current timestamp,

// an error will be returned from read().

void clearSkipFrame();

bool getSkipFrame(int64_t *timeUs) const;

void setSkipFrame(int64_t timeUs);

MPEG4Extractor.h

struct MediaSource : public RefBase {

MediaSource();

// To be called before any other methods on this object, except

// getFormat().

virtual status_t start(MetaData *params = NULL) = 0;

// Any blocking read call returns immediately with a result of NO_INIT.

// It is an error to call any methods other than start after this call

// returns. Any buffers the object may be holding onto at the time of

// the stop() call are released.

// Also, it is imperative that any buffers output by this object and

// held onto by callers be released before a call to stop() !!!

virtual status_t stop() = 0;

// Returns the format of the data output by this media source.

virtual sp<MetaData> getFormat() = 0;

struct ReadOptions;

// Returns a new buffer of data. Call blocks until a

// buffer is available, an error is encountered of the end of the stream

// is reached.

// End of stream is signalled by a result of ERROR_END_OF_STREAM.

// A result of INFO_FORMAT_CHANGED indicates that the format of this

// MediaSource has changed mid-stream, the client can continue reading

// but should be prepared for buffers of the new configuration.

virtual status_t read(

MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;

DataSource

class MPEG4Extractor : public MediaExtractor {

public:

// Extractor assumes ownership of "source".

MPEG4Extractor(const sp<DataSource> &source);

virtual size_t countTracks();

virtual sp<MediaSource> getTrack(size_t index);

virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);

virtual sp<MetaData> getMetaData();

protected:

virtual ~MPEG4Extractor();

DataSource.h

class DataSource : public RefBase {

public:

enum Flags {

kWantsPrefetching = 1,

kStreamedFromLocalHost = 2,

kIsCachingDataSource = 4,

};

static sp<DataSource> CreateFromURI(

const char *uri,

const KeyedVector<String8, String8> *headers = NULL);

DataSource() {}

virtual status_t initCheck() const = 0;

virtual ssize_t readAt(off_t offset, void *data, size_t size) = 0;

// Convenience methods:

bool getUInt16(off_t offset, uint16_t *x);

// May return ERROR_UNSUPPORTED.

virtual status_t getSize(off_t *size);

virtual uint32_t flags() {

return 0;

}

DataSource.cpp

////////////////////////////////////////////////////////////////////////////

bool sniff(String8 *mimeType, float *confidence, sp<AMessage> *meta);

// The sniffer can optionally fill in "meta" with an AMessage containing

// a dictionary of values that helps the corresponding extractor initialize

// its state without duplicating effort already exerted by the sniffer.

typedef bool (*SnifferFunc)(

const sp<DataSource> &source, String8 *mimeType,

float *confidence, sp<AMessage> *meta);

static void RegisterSniffer(SnifferFunc func);

static void RegisterDefaultSniffers();

protected:

virtual ~DataSource() {}

private:

static Mutex gSnifferMutex;

static List<SnifferFunc> gSniffers;

DataSource(const DataSource &);

DataSource &operator=(const DataSource &);

};

// static

sp<DataSource> DataSource::CreateFromURI(

const char *uri, const KeyedVector<String8, String8> *headers) {

sp<DataSource> source;

if (!strncasecmp("file://", uri, 7)) {

source = new FileSource(uri + 7);

} else if (!strncasecmp("http://", uri, 7)) {

sp<NuHTTPDataSource> httpSource = new NuHTTPDataSource;

if (httpSource->connect(uri, headers) != OK) {

return NULL;

}

source = new NuCachedSource2(httpSource);

} else {

// Assume it's a filename.

source = new FileSource(uri);

}

if (source == NULL || source->initCheck() != OK) {

return NULL;

}

return source;

}

bool DataSource::sniff(

String8 *mimeType, float *confidence, sp<AMessage> *meta) {

*mimeType = "";

*confidence = 0.0f;

meta->clear();

Mutex::Autolock autoLock(gSnifferMutex);

for (List<SnifferFunc>::iterator it = gSniffers.begin();

it != gSniffers.end(); ++it) {

String8 newMimeType;

float newConfidence;

sp<AMessage> newMeta;

if ((*it)(this, &newMimeType, &newConfidence, &newMeta)) {

if (newConfidence > *confidence) {

*mimeType = newMimeType;

*confidence = newConfidence;

*meta = newMeta;

}

}

}

return *confidence > 0.0;

}

Learn more about creating dynamic, engaging presentations with Prezi