diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/omx/omx_test.cc | 163 | ||||
-rw-r--r-- | media/omx/omx_test.gyp | 30 | ||||
-rw-r--r-- | media/omx/omx_video_decoder.cc | 10 | ||||
-rw-r--r-- | media/omx/omx_video_decoder.h | 10 |
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_; |