summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/omx/omx_test.cc163
-rw-r--r--media/omx/omx_test.gyp30
-rw-r--r--media/omx/omx_video_decoder.cc10
-rw-r--r--media/omx/omx_video_decoder.h10
4 files changed, 205 insertions, 8 deletions
diff --git a/media/omx/omx_test.cc b/media/omx/omx_test.cc
new file mode 100644
index 0000000..306a2fd
--- /dev/null
+++ b/media/omx/omx_test.cc
@@ -0,0 +1,163 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+// A test program that drives an OpenMAX video decoder module. This program
+// will take video in elementary stream and read into the decoder.
+// Usage of this program:
+// ./omx_test --file=<file> --component=<component> --codec=<codec>
+// <file> = Input file name
+// <component> = Name of the OpenMAX component
+// <codec> = Codec to be used, available codecs: h264, vc1, mpeg4, h263.
+
+#include "base/at_exit.h"
+#include "base/command_line.h"
+#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
+#include "media/omx/input_buffer.h"
+#include "media/omx/omx_video_decoder.h"
+
+// This is the driver object to feed the decoder with data from a file.
+// It also provides callbacks for the decoder to receive events from the
+// decoder.
+class TestApp {
+ public:
+ TestApp(const char* filename,
+ const char* component,
+ media::OmxVideoDecoder::Codec codec)
+ : filename_(filename),
+ component_(component),
+ codec_(codec),
+ stopped_(false),
+ error_(false) {
+ }
+
+ void StopCallback() {
+ // If this callback is received, mark the |stopped_| flag so that we don't
+ // feed more buffers into the decoder.
+ // We need to exit the current message loop because we have no more work
+ // to do on the message loop. This is done by calling
+ // message_loop_.Quit().
+ stopped_ = true;
+ message_loop_.Quit();
+ }
+
+ void ErrorCallback() {
+ // In case of error, this method is called. Mark the error flag and
+ // exit the message loop because we have no more work to do.
+ printf("Error callback received!\n");
+ error_ = true;
+ message_loop_.Quit();
+ }
+
+ void FeedCallback(media::InputBuffer* buffer) {
+ // We receive this callback when the decoder has consumed an input buffer.
+ // In this case, delete the previous buffer and enqueue a new one.
+ // There are some conditions we don't want to enqueue, for example when
+ // the last buffer is an end-of-stream buffer, when we have stopped, and
+ // when we have received an error.
+ bool eos = buffer->Eos();
+ delete buffer;
+ if (!eos && !stopped_ && !error_)
+ FeedDecoder();
+ }
+
+ void ReadCompleteCallback(uint8* buffer, int size) {
+ // This callback is received when the decoder has completed a decoding
+ // task and given us some output data. The buffer is owned by the decoder.
+ if (stopped_ || error_)
+ return;
+
+ // If we are readding to the end, then stop.
+ if (!size) {
+ decoder_->Stop(NewCallback(this, &TestApp::StopCallback));
+ return;
+ }
+
+ // Read one more from the decoder.
+ decoder_->Read(NewCallback(this, &TestApp::ReadCompleteCallback));
+ }
+
+ void FeedDecoder() {
+ // This method feeds the decoder with 32KB of input data.
+ const int kSize = 32768;
+ uint8* data = new uint8[kSize];
+ int read = fread(data, 1, kSize, file_);
+ decoder_->Feed(new media::InputBuffer(data, read),
+ NewCallback(this, &TestApp::FeedCallback));
+ }
+
+ void Run() {
+ // Open the input file.
+ file_ = fopen(filename_, "rb");
+ if (!file_) {
+ printf("Error - can't open file %s\n", filename_);
+ return;
+ }
+
+ // Setup the decoder with the message loop of the current thread. Also
+ // setup component name, codec and callbacks.
+ decoder_ = new media::OmxVideoDecoder(&message_loop_);
+ decoder_->Setup(component_, codec_);
+ decoder_->SetErrorCallback(NewCallback(this, &TestApp::ErrorCallback));
+
+ // Start the decoder.
+ decoder_->Start();
+ for (int i = 0; i < 20; ++i)
+ FeedDecoder();
+ decoder_->Read(NewCallback(this, &TestApp::ReadCompleteCallback));
+
+ // Execute the message loop so that we can run tasks on it. This call
+ // will return when we call message_loop_.Quit().
+ message_loop_.Run();
+ }
+
+ scoped_refptr<media::OmxVideoDecoder> decoder_;
+ MessageLoop message_loop_;
+ const char* filename_;
+ const char* component_;
+ media::OmxVideoDecoder::Codec codec_;
+ FILE* file_;
+ bool stopped_;
+ bool error_;
+};
+
+int main(int argc, char** argv) {
+ base::AtExitManager at_exit_manager;
+
+ CommandLine::Init(argc, argv);
+ const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
+
+ if (argc < 2) {
+ printf("Usage: omx_test --file=FILE --component=COMPONENT --codec=CODEC\n");
+ printf(" COMPONENT: OpenMAX component name\n");
+ printf(" CODEC: h264/mpeg4/h263/vc1\n");
+ return 1;
+ }
+
+ std::string filename = cmd_line->GetSwitchValueASCII("file");
+ std::string component = cmd_line->GetSwitchValueASCII("component");
+ std::string codec = cmd_line->GetSwitchValueASCII("codec");
+
+ media::OmxVideoDecoder::Codec codec_id = media::OmxVideoDecoder::kCodecNone;
+ if (codec == "h264")
+ codec_id = media::OmxVideoDecoder::kCodecH264;
+ else if (codec == "mpeg4")
+ codec_id = media::OmxVideoDecoder::kCodecMpeg4;
+ else if (codec == "h263")
+ codec_id = media::OmxVideoDecoder::kCodecH263;
+ else if (codec == "vc1")
+ codec_id = media::OmxVideoDecoder::kCodecVc1;
+ else {
+ printf("Unknown codec.\n");
+ return 1;
+ }
+
+ // Create a TestApp object and run the decoder.
+ TestApp test(filename.c_str(), component.c_str(), codec_id);
+
+ // This call will run the decoder until EOS is reached or an error
+ // is encountered.
+ test.Run();
+ return 0;
+}
diff --git a/media/omx/omx_test.gyp b/media/omx/omx_test.gyp
new file mode 100644
index 0000000..0e2fcaa
--- /dev/null
+++ b/media/omx/omx_test.gyp
@@ -0,0 +1,30 @@
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'conditions': [
+ ['OS=="linux"', {
+ 'targets' : [
+ {
+ 'target_name': 'omx_test',
+ 'type': 'executable',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../third_party/openmax/openmax.gyp:il',
+ ],
+ 'sources': [
+ 'input_buffer.cc',
+ 'input_buffer.h',
+ 'omx_test.cc',
+ 'omx_video_decoder.cc',
+ 'omx_video_decoder.h',
+ ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/media/omx/omx_video_decoder.cc b/media/omx/omx_video_decoder.cc
index 4142ab8..1b2f416 100644
--- a/media/omx/omx_video_decoder.cc
+++ b/media/omx/omx_video_decoder.cc
@@ -35,13 +35,14 @@ OmxVideoDecoder::~OmxVideoDecoder() {
DCHECK(output_queue_.empty());
}
-void OmxVideoDecoder::Setup(Codec codec) {
- DCHECK_EQ(kEmpty, GetState());
+void OmxVideoDecoder::Setup(const char* component, Codec codec) {
+ DCHECK_EQ(kEmpty, state_);
+ component_ = component;
codec_ = codec;
}
void OmxVideoDecoder::SetErrorCallback(Callback* callback) {
- DCHECK_EQ(kEmpty, GetState());
+ DCHECK_EQ(kEmpty, state_);
error_callback_.reset(callback);
}
@@ -278,7 +279,8 @@ void OmxVideoDecoder::Transition_EmptyToLoaded() {
// 2. Get the handle to the component. After OMX_GetHandle(),
// the component is in loaded state.
- component = GetComponentName(codec_);
+ // TODO(hclam): We should have a list of componant names instead.
+ component = component_;
omxresult = OMX_GetHandle((OMX_HANDLETYPE*)(&decoder_handle_),
(OMX_STRING)component, this, &callback);
if (omxresult != OMX_ErrorNone) {
diff --git a/media/omx/omx_video_decoder.h b/media/omx/omx_video_decoder.h
index 3da80b9..baf3c51 100644
--- a/media/omx/omx_video_decoder.h
+++ b/media/omx/omx_video_decoder.h
@@ -11,7 +11,7 @@
// // Initialization.
// MessageLoop message_loop;
// OmxVideoDecoder* decoder = new OmxVideoDecoder(&message_loop);
-// decoder->Setup(kCodecH264);
+// decoder->Setup(component_name, kCodecH264);
// decoder->SetErrorCallback(NewCallback(this, &Client::ErrorCallback));
//
// // Start is asynchronous. But we don't need to wait for it to proceed.
@@ -104,9 +104,9 @@ class OmxVideoDecoder : public base::RefCountedThreadSafe<OmxVideoDecoder> {
OmxVideoDecoder(MessageLoop* message_loop);
virtual ~OmxVideoDecoder();
- // Set the input codec format.
- // TODO(hclam): Add input format and output format.
- void Setup(Codec codec);
+ // Set the component name and input codec format.
+ // TODO(hclam): Add input format and output format. Also remove |component|.
+ void Setup(const char* component, Codec codec);
// Set the error callback. In case of error the callback will be called.
void SetErrorCallback(Callback* callback);
@@ -289,6 +289,8 @@ class OmxVideoDecoder : public base::RefCountedThreadSafe<OmxVideoDecoder> {
State state_;
State next_state_;
+ // TODO(hclam): We should keep a list of component names.
+ const char* component_;
Codec codec_;
MessageLoop* message_loop_;