summaryrefslogtreecommitdiffstats
path: root/cmds/stagefright
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2009-08-14 14:37:10 -0700
committerAndreas Huber <andih@google.com>2009-08-17 10:24:50 -0700
commit693d271e62a3726689ff68f4505ba49228eb94b2 (patch)
treedcc952183cfd766d385c25665571be967926cf89 /cmds/stagefright
parent59ecb64c9629ab02329f8240c85b820ee0c98a2e (diff)
downloadframeworks_av-693d271e62a3726689ff68f4505ba49228eb94b2.zip
frameworks_av-693d271e62a3726689ff68f4505ba49228eb94b2.tar.gz
frameworks_av-693d271e62a3726689ff68f4505ba49228eb94b2.tar.bz2
Squashed commit of the following:
commit 5bb012f0065f7ffaaeb4f569d71f0e3a8d6b19c3 Author: Andreas Huber <andih@google.com> Date: Fri Aug 14 10:40:08 2009 -0700 An attempt at fixing export using the qcom encoders. More quirks. commit 0690e76bfa48118a68287ccf1bbfa82febaa620c Author: Andreas Huber <andih@google.com> Date: Fri Aug 14 09:08:28 2009 -0700 Callbacks are now dispatched from a separate thread in OMX. commit c6571a039526df29b6343f9a1971dbc019088c61 Author: Andreas Huber <andih@google.com> Date: Thu Aug 13 15:42:25 2009 -0700 Massive API changes throughout stagefright, smart pointers everywhere. commit 900612af6a0555664d9ba195112cd859491265f4 Author: Andreas Huber <andih@google.com> Date: Thu Aug 13 13:33:12 2009 -0700 OMXCodecs now properly shutdown. commit 96732f05e1b0603dcd1b11f16a23512592eeb4f5 Author: Andreas Huber <andih@google.com> Date: Thu Aug 13 12:04:04 2009 -0700 More work on JPEG decoding using the hardware OMX component. commit 63839a073ac393e3a130434ba467969053b694ad Author: Andreas Huber <andih@google.com> Date: Wed Aug 12 13:13:31 2009 -0700 An attempt to drive the JPEG decoder OMX node. commit 3ac2fe5ab2926eda81b2123610b2434c645294ff Author: Andreas Huber <andih@google.com> Date: Tue Aug 11 16:38:21 2009 -0700 Renamed StateMachine to OMXCodec and put it in its proper place. commit 247da75a96bf8881956413023dd49a84d5b4f5b2 Author: Andreas Huber <andih@google.com> Date: Tue Aug 11 16:06:19 2009 -0700 Statemachine is now a full-fledged MediaSource. commit 045244f6771fa0b9b329495c953afda900a84b71 Author: Andreas Huber <andih@google.com> Date: Fri Aug 7 09:16:54 2009 -0700 Properly setup the input format when exporting to AMR audio. commit 271b984cb32c5cd9e46e3f90ae121f334e4b8da9 Author: Andreas Huber <andih@google.com> Date: Thu Aug 6 09:59:38 2009 -0700 Added some code to test audio encoding to the OMX harness. commit 79af4748e4af33bd66d3fbac606e332a69741cf4 Author: Andreas Huber <andih@google.com> Date: Wed Aug 5 14:36:22 2009 -0700 Merge the old OMXDecoder and the new, shiny, StateMachine code. commit 91cf5dd77a8762bc10a0b2ffce35e3bbeb262231 Author: Andreas Huber <andih@google.com> Date: Tue Aug 4 17:41:43 2009 -0700 A new harness to test OMX node compliance (and quirks).
Diffstat (limited to 'cmds/stagefright')
-rw-r--r--cmds/stagefright/Android.mk9
-rw-r--r--cmds/stagefright/record.cpp135
-rw-r--r--cmds/stagefright/stagefright.cpp372
3 files changed, 375 insertions, 141 deletions
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index e6d0503..4576b8e 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -10,8 +10,7 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_C_INCLUDES:= \
frameworks/base/media/libstagefright \
- $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
- $(TOP)/external/opencore/android
+ $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
LOCAL_CFLAGS += -Wno-multichar
@@ -31,8 +30,7 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_C_INCLUDES:= \
frameworks/base/media/libstagefright \
- $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
- $(TOP)/external/opencore/android
+ $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
LOCAL_CFLAGS += -Wno-multichar
@@ -52,8 +50,7 @@ include $(BUILD_EXECUTABLE)
#
# LOCAL_C_INCLUDES:= \
# frameworks/base/media/libstagefright \
-# $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
-# $(TOP)/external/opencore/android
+# $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
#
# LOCAL_CFLAGS += -Wno-multichar
#
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index cd54958..cf2962b 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -25,6 +25,7 @@
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/MmapSource.h>
#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/OMXDecoder.h>
using namespace android;
@@ -32,18 +33,38 @@ using namespace android;
class DummySource : public MediaSource {
public:
DummySource(int width, int height)
- : mSize((width * height * 3) / 2) {
+ : mWidth(width),
+ mHeight(height),
+ mSize((width * height * 3) / 2) {
mGroup.add_buffer(new MediaBuffer(mSize));
}
- virtual ::status_t getMaxSampleSize(size_t *max_size) {
+ virtual sp<MetaData> getFormat() {
+ sp<MetaData> meta = new MetaData;
+ meta->setInt32(kKeyWidth, mWidth);
+ meta->setInt32(kKeyHeight, mHeight);
+ meta->setCString(kKeyMIMEType, "video/raw");
+
+ return meta;
+ }
+
+ virtual status_t getMaxSampleSize(size_t *max_size) {
*max_size = mSize;
- return ::OK;
+ return OK;
+ }
+
+ virtual status_t start(MetaData *params) {
+ return OK;
+ }
+
+ virtual status_t stop() {
+ return OK;
}
- virtual ::status_t read(MediaBuffer **buffer) {
- ::status_t err = mGroup.acquire_buffer(buffer);
- if (err != ::OK) {
+ virtual status_t read(
+ MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
+ status_t err = mGroup.acquire_buffer(buffer);
+ if (err != OK) {
return err;
}
@@ -51,34 +72,34 @@ public:
memset((*buffer)->data(), x, mSize);
(*buffer)->set_range(0, mSize);
- return ::OK;
+ return OK;
}
+protected:
+ virtual ~DummySource() {}
+
private:
MediaBufferGroup mGroup;
+ int mWidth, mHeight;
size_t mSize;
DummySource(const DummySource &);
DummySource &operator=(const DummySource &);
};
-int main(int argc, char **argv) {
- android::ProcessState::self()->startThreadPool();
+#define USE_OMX_CODEC 1
-#if 1
- if (argc != 2) {
- fprintf(stderr, "usage: %s filename\n", argv[0]);
- return 1;
- }
+sp<MediaSource> createSource(const char *filename) {
+ sp<MediaSource> source;
- MPEG4Extractor extractor(new MmapSource(argv[1]));
- int num_tracks;
- assert(extractor.countTracks(&num_tracks) == ::OK);
+ sp<MPEG4Extractor> extractor =
+ new MPEG4Extractor(new MmapSource(filename));
+
+ size_t num_tracks = extractor->countTracks();
- MediaSource *source = NULL;
sp<MetaData> meta;
- for (int i = 0; i < num_tracks; ++i) {
- meta = extractor.getTrackMetaData(i);
+ for (size_t i = 0; i < num_tracks; ++i) {
+ meta = extractor->getTrackMetaData(i);
assert(meta.get() != NULL);
const char *mime;
@@ -90,48 +111,75 @@ int main(int argc, char **argv) {
continue;
}
- if (extractor.getTrack(i, &source) != ::OK) {
- source = NULL;
- continue;
- }
+ source = extractor->getTrack(i);
break;
}
- if (source == NULL) {
- fprintf(stderr, "Unable to find a suitable video track.\n");
+ return source;
+}
+
+int main(int argc, char **argv) {
+ android::ProcessState::self()->startThreadPool();
+
+#if 1
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s filename\n", argv[0]);
return 1;
}
OMXClient client;
assert(client.connect() == android::OK);
- OMXDecoder *decoder = OMXDecoder::Create(&client, meta);
- decoder->setSource(source);
+#if 0
+ sp<MediaSource> source = createSource(argv[1]);
+
+ if (source == NULL) {
+ fprintf(stderr, "Unable to find a suitable video track.\n");
+ return 1;
+ }
+
+ sp<MetaData> meta = source->getFormat();
+
+#if USE_OMX_CODEC
+ sp<OMXCodec> decoder = OMXCodec::Create(
+ client.interface(), meta, false /* createEncoder */, source);
+#else
+ sp<OMXDecoder> decoder = OMXDecoder::Create(
+ &client, meta, false /* createEncoder */, source);
+#endif
int width, height;
bool success = meta->findInt32(kKeyWidth, &width);
success = success && meta->findInt32(kKeyHeight, &height);
assert(success);
+#else
+ int width = 320;
+ int height = 240;
+ sp<MediaSource> decoder = new DummySource(width, height);
+#endif
sp<MetaData> enc_meta = new MetaData;
- enc_meta->setCString(kKeyMIMEType, "video/3gpp");
- // enc_meta->setCString(kKeyMIMEType, "video/mp4v-es");
+ // enc_meta->setCString(kKeyMIMEType, "video/3gpp");
+ enc_meta->setCString(kKeyMIMEType, "video/mp4v-es");
enc_meta->setInt32(kKeyWidth, width);
enc_meta->setInt32(kKeyHeight, height);
- OMXDecoder *encoder =
- OMXDecoder::Create(&client, enc_meta, true /* createEncoder */);
-
- encoder->setSource(decoder);
- // encoder->setSource(meta, new DummySource(width, height));
+#if USE_OMX_CODEC
+ sp<OMXCodec> encoder =
+ OMXCodec::Create(
+ client.interface(), enc_meta, true /* createEncoder */, decoder);
+#else
+ sp<OMXDecoder> encoder = OMXDecoder::Create(
+ &client, enc_meta, true /* createEncoder */, decoder);
+#endif
#if 1
- MPEG4Writer writer("/sdcard/output.mp4");
- writer.addSource(enc_meta, encoder);
- writer.start();
+ sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
+ writer->addSource(enc_meta, encoder);
+ writer->start();
sleep(20);
printf("stopping now.\n");
- writer.stop();
+ writer->stop();
#else
encoder->start();
@@ -146,16 +194,7 @@ int main(int argc, char **argv) {
encoder->stop();
#endif
- delete encoder;
- encoder = NULL;
-
- delete decoder;
- decoder = NULL;
-
client.disconnect();
-
- delete source;
- source = NULL;
#endif
#if 0
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 7e23574..b2de67a 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -16,9 +16,6 @@
#include <sys/time.h>
-#undef NDEBUG
-#include <assert.h>
-
#include <pthread.h>
#include <stdlib.h>
@@ -30,12 +27,15 @@
#include <media/stagefright/ESDS.h>
#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaPlayerImpl.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MmapSource.h>
#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/OMXDecoder.h>
#include "WaveWriter.h"
@@ -44,50 +44,236 @@ using namespace android;
////////////////////////////////////////////////////////////////////////////////
-static bool convertToWav(
- OMXClient *client, const sp<MetaData> &meta, MediaSource *source) {
- printf("convertToWav\n");
+struct JPEGSource : public MediaSource {
+ // Assumes ownership of "source".
+ JPEGSource(const sp<DataSource> &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);
+
+protected:
+ virtual ~JPEGSource();
+
+private:
+ sp<DataSource> mSource;
+ MediaBufferGroup *mGroup;
+ bool mStarted;
+ off_t mSize;
+ int32_t mWidth, mHeight;
+ off_t mOffset;
+
+ status_t parseJPEG();
+
+ JPEGSource(const JPEGSource &);
+ JPEGSource &operator=(const JPEGSource &);
+};
+
+JPEGSource::JPEGSource(const sp<DataSource> &source)
+ : mSource(source),
+ mGroup(NULL),
+ mStarted(false),
+ mSize(0),
+ mWidth(0),
+ mHeight(0),
+ mOffset(0) {
+ CHECK_EQ(parseJPEG(), OK);
+}
+
+JPEGSource::~JPEGSource() {
+ if (mStarted) {
+ stop();
+ }
+}
+
+status_t JPEGSource::start(MetaData *) {
+ if (mStarted) {
+ return UNKNOWN_ERROR;
+ }
- OMXDecoder *decoder = OMXDecoder::Create(client, meta);
+ if (mSource->getSize(&mSize) != OK) {
+ return UNKNOWN_ERROR;
+ }
- int32_t sampleRate;
- bool success = meta->findInt32(kKeySampleRate, &sampleRate);
- assert(success);
+ mGroup = new MediaBufferGroup;
+ mGroup->add_buffer(new MediaBuffer(mSize));
- int32_t numChannels;
- success = meta->findInt32(kKeyChannelCount, &numChannels);
- assert(success);
+ mOffset = 0;
- const char *mime;
- success = meta->findCString(kKeyMIMEType, &mime);
- assert(success);
+ mStarted = true;
+
+ return OK;
+}
- if (!strcasecmp("audio/3gpp", mime)) {
- numChannels = 1; // XXX
+status_t JPEGSource::stop() {
+ if (!mStarted) {
+ return UNKNOWN_ERROR;
}
- WaveWriter writer("/sdcard/Music/shoutcast.wav", numChannels, sampleRate);
+ delete mGroup;
+ mGroup = NULL;
- decoder->setSource(source);
- for (int i = 0; i < 100; ++i) {
- MediaBuffer *buffer;
+ mStarted = false;
- ::status_t err = decoder->read(&buffer);
- if (err != ::OK) {
- break;
- }
+ return OK;
+}
+
+sp<MetaData> JPEGSource::getFormat() {
+ sp<MetaData> meta = new MetaData;
+ meta->setCString(kKeyMIMEType, "image/jpeg");
+ meta->setInt32(kKeyWidth, mWidth);
+ meta->setInt32(kKeyHeight, mHeight);
+
+ return meta;
+}
+
+status_t JPEGSource::read(
+ MediaBuffer **out, const ReadOptions *options) {
+ *out = NULL;
- writer.Append((const char *)buffer->data() + buffer->range_offset(),
- buffer->range_length());
+ int64_t seekTimeUs;
+ if (options != NULL && options->getSeekTo(&seekTimeUs)) {
+ return UNKNOWN_ERROR;
+ }
+
+ MediaBuffer *buffer;
+ mGroup->acquire_buffer(&buffer);
+
+ ssize_t n = mSource->read_at(mOffset, buffer->data(), mSize - mOffset);
+ if (n <= 0) {
buffer->release();
buffer = NULL;
+
+ return UNKNOWN_ERROR;
+ }
+
+ buffer->set_range(0, n);
+
+ mOffset += n;
+
+ *out = buffer;
+
+ return OK;
+}
+
+#define JPEG_SOF0 0xC0 /* nStart Of Frame N*/
+#define JPEG_SOF1 0xC1 /* N indicates which compression process*/
+#define JPEG_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use*/
+#define JPEG_SOF3 0xC3
+#define JPEG_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers*/
+#define JPEG_SOF6 0xC6
+#define JPEG_SOF7 0xC7
+#define JPEG_SOF9 0xC9
+#define JPEG_SOF10 0xCA
+#define JPEG_SOF11 0xCB
+#define JPEG_SOF13 0xCD
+#define JPEG_SOF14 0xCE
+#define JPEG_SOF15 0xCF
+#define JPEG_SOI 0xD8 /* nStart Of Image (beginning of datastream)*/
+#define JPEG_EOI 0xD9 /* End Of Image (end of datastream)*/
+#define JPEG_SOS 0xDA /* nStart Of Scan (begins compressed data)*/
+#define JPEG_JFIF 0xE0 /* Jfif marker*/
+#define JPEG_EXIF 0xE1 /* Exif marker*/
+#define JPEG_COM 0xFE /* COMment */
+#define JPEG_DQT 0xDB
+#define JPEG_DHT 0xC4
+#define JPEG_DRI 0xDD
+
+status_t JPEGSource::parseJPEG() {
+ mWidth = 0;
+ mHeight = 0;
+
+ off_t i = 0;
+
+ uint16_t soi;
+ if (!mSource->getUInt16(i, &soi)) {
+ return ERROR_IO;
}
- delete decoder;
- decoder = NULL;
+ i += 2;
+
+ if (soi != 0xffd8) {
+ return UNKNOWN_ERROR;
+ }
+
+ for (;;) {
+ uint8_t marker;
+ if (mSource->read_at(i++, &marker, 1) != 1) {
+ return ERROR_IO;
+ }
+
+ CHECK_EQ(marker, 0xff);
+
+ if (mSource->read_at(i++, &marker, 1) != 1) {
+ return ERROR_IO;
+ }
+
+ CHECK(marker != 0xff);
+
+ uint16_t chunkSize;
+ if (!mSource->getUInt16(i, &chunkSize)) {
+ return ERROR_IO;
+ }
+
+ i += 2;
+
+ if (chunkSize < 2) {
+ return UNKNOWN_ERROR;
+ }
+
+ switch (marker) {
+ case JPEG_SOS:
+ {
+ return (mWidth > 0 && mHeight > 0) ? OK : UNKNOWN_ERROR;
+ }
+
+ case JPEG_EOI:
+ {
+ return UNKNOWN_ERROR;
+ }
+
+ case JPEG_SOF0:
+ case JPEG_SOF1:
+ case JPEG_SOF3:
+ case JPEG_SOF5:
+ case JPEG_SOF6:
+ case JPEG_SOF7:
+ case JPEG_SOF9:
+ case JPEG_SOF10:
+ case JPEG_SOF11:
+ case JPEG_SOF13:
+ case JPEG_SOF14:
+ case JPEG_SOF15:
+ {
+ uint16_t width, height;
+ if (!mSource->getUInt16(i + 1, &height)
+ || !mSource->getUInt16(i + 3, &width)) {
+ return ERROR_IO;
+ }
+
+ mWidth = width;
+ mHeight = height;
+
+ i += chunkSize - 2;
+ break;
+ }
+
+ default:
+ {
+ // Skip chunk
+
+ i += chunkSize - 2;
+
+ break;
+ }
+ }
+ }
- return true;
+ return OK;
}
////////////////////////////////////////////////////////////////////////////////
@@ -99,6 +285,48 @@ static int64_t getNowUs() {
return (int64_t)tv.tv_usec + tv.tv_sec * 1000000;
}
+#define USE_OMX_CODEC 1
+
+static void playSource(OMXClient *client, const sp<MediaSource> &source) {
+ 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(
+ client->interface(), meta, false /* createEncoder */, source);
+#endif
+
+ if (decoder == NULL) {
+ return;
+ }
+
+ decoder->start();
+
+ int64_t startTime = getNowUs();
+
+ int n = 0;
+ MediaBuffer *buffer;
+ status_t err;
+ while ((err = decoder->read(&buffer)) == OK) {
+ if ((++n % 16) == 0) {
+ printf(".");
+ fflush(stdout);
+ }
+
+ buffer->release();
+ buffer = NULL;
+ }
+ decoder->stop();
+ printf("\n");
+
+ int64_t delay = getNowUs() - startTime;
+ printf("avg. %.2f fps\n", n * 1E6 / delay);
+
+ printf("decoded a total of %d frame(s).\n", n);
+}
+
int main(int argc, char **argv) {
android::ProcessState::self()->startThreadPool();
@@ -108,10 +336,10 @@ int main(int argc, char **argv) {
sp<IBinder> binder = sm->getService(String16("media.player"));
sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
- assert(service.get() != NULL);
+ CHECK(service.get() != NULL);
sp<IOMX> omx = service->createOMX();
- assert(omx.get() != NULL);
+ CHECK(omx.get() != NULL);
List<String8> list;
omx->list_nodes(&list);
@@ -128,82 +356,52 @@ int main(int argc, char **argv) {
--argc;
}
-#if 0
- MediaPlayerImpl player(argv[1]);
- player.play();
-
- sleep(10000);
-#else
DataSource::RegisterDefaultSniffers();
OMXClient client;
status_t err = client.connect();
- MmapSource *dataSource = new MmapSource(argv[1]);
- MediaExtractor *extractor = MediaExtractor::Create(dataSource);
- dataSource = NULL;
-
- int numTracks;
- err = extractor->countTracks(&numTracks);
-
- sp<MetaData> meta;
- int i;
- for (i = 0; i < numTracks; ++i) {
- meta = extractor->getTrackMetaData(i);
+ sp<MmapSource> dataSource = new MmapSource(argv[1]);
- const char *mime;
- meta->findCString(kKeyMIMEType, &mime);
-
- if (audioOnly && !strncasecmp(mime, "audio/", 6)) {
- break;
- }
+ bool isJPEG = false;
- if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
- break;
- }
+ size_t len = strlen(argv[1]);
+ if (len >= 4 && !strcasecmp(argv[1] + len - 4, ".jpg")) {
+ isJPEG = true;
}
- OMXDecoder *decoder = OMXDecoder::Create(&client, meta);
+ sp<MediaSource> mediaSource;
- if (decoder != NULL) {
- MediaSource *source;
- err = extractor->getTrack(i, &source);
+ if (isJPEG) {
+ mediaSource = new JPEGSource(dataSource);
+ } else {
+ sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
- decoder->setSource(source);
+ size_t numTracks = extractor->countTracks();
- decoder->start();
+ sp<MetaData> meta;
+ size_t i;
+ for (i = 0; i < numTracks; ++i) {
+ meta = extractor->getTrackMetaData(i);
- int64_t startTime = getNowUs();
+ const char *mime;
+ meta->findCString(kKeyMIMEType, &mime);
- int n = 0;
- MediaBuffer *buffer;
- while ((err = decoder->read(&buffer)) == OK) {
- if ((++n % 16) == 0) {
- printf(".");
- fflush(stdout);
+ if (audioOnly && !strncasecmp(mime, "audio/", 6)) {
+ break;
}
- buffer->release();
- buffer = NULL;
+ if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
+ break;
+ }
}
- decoder->stop();
- printf("\n");
-
- int64_t delay = getNowUs() - startTime;
- printf("avg. %.2f fps\n", n * 1E6 / delay);
- delete decoder;
- decoder = NULL;
-
- delete source;
- source = NULL;
+ mediaSource = extractor->getTrack(i);
}
- delete extractor;
- extractor = NULL;
+ playSource(&client, mediaSource);
client.disconnect();
-#endif
return 0;
}