diff options
Diffstat (limited to 'media/omx/omx_test.cc')
-rw-r--r-- | media/omx/omx_test.cc | 208 |
1 files changed, 184 insertions, 24 deletions
diff --git a/media/omx/omx_test.cc b/media/omx/omx_test.cc index 0a44a70..08d91f0 100644 --- a/media/omx/omx_test.cc +++ b/media/omx/omx_test.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this +// Copyright (c) 2010 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. @@ -15,6 +15,7 @@ #include "base/file_util.h" #include "base/message_loop.h" #include "base/scoped_ptr.h" +#include "base/time.h" #include "media/omx/input_buffer.h" #include "media/omx/omx_codec.h" @@ -23,15 +24,21 @@ // decoder. class TestApp { public: - TestApp(const char* filename, + TestApp(const char* input_filename, + const char* output_filename, const char* component, - media::OmxCodec::Codec codec, + media::OmxCodec::OmxMediaFormat& input_format, + media::OmxCodec::OmxMediaFormat& output_format, bool simulate_copy) - : filename_(filename), + : input_filename_(input_filename), + output_filename_(output_filename), component_(component), - codec_(codec), + input_format_(input_format), + output_format_(output_format), simulate_copy_(simulate_copy), copy_buf_size_(0), + input_file_(NULL), + output_file_(NULL), stopped_(false), error_(false) { } @@ -82,36 +89,52 @@ class TestApp { decoder_->Read(NewCallback(this, &TestApp::ReadCompleteCallback)); // Copy the output of the decoder to user memory. - if (simulate_copy_) { + if (simulate_copy_ || output_file_) { // |output_file_| implies a copy. if (size > copy_buf_size_) { copy_buf_.reset(new uint8[size]); copy_buf_size_ = size; } memcpy(copy_buf_.get(), buffer, size); + if (output_file_) + fwrite(copy_buf_.get(), sizeof(uint8), size, output_file_); } + + // could OMX IL return patial sample for decoder? + frame_count_++; + bit_count_ += size << 3; } 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_); + int read = fread(data, 1, kSize, input_file_); decoder_->Feed(new media::InputBuffer(data, read), NewCallback(this, &TestApp::FeedCallback)); } void Run() { // Open the input file. - file_ = file_util::OpenFile(filename_, "rb"); - if (!file_) { - printf("Error - can't open file %s\n", filename_); + input_file_ = file_util::OpenFile(input_filename_, "rb"); + if (!input_file_) { + printf("Error - can't open file %s\n", input_filename_); return; } + // Open the dump file. + if (strlen(output_filename_)) { + output_file_ = file_util::OpenFile(output_filename_, "wb"); + if (!input_file_) { + fclose(input_file_); + printf("Error - can't open dump file %s\n", output_filename_); + return; + } + } + // Setup the decoder with the message loop of the current thread. Also // setup component name, codec and callbacks. decoder_ = new media::OmxCodec(&message_loop_); - decoder_->Setup(component_, codec_); + decoder_->Setup(component_, input_format_, output_format_); decoder_->SetErrorCallback(NewCallback(this, &TestApp::ErrorCallback)); // Start the decoder. @@ -123,21 +146,100 @@ class TestApp { // 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(); + + fclose(input_file_); + if (output_file_) + fclose(output_file_); + } + + void StartProfiler() { + start_time_ = base::Time::Now(); + frame_count_ = 0; + bit_count_ = 0; + } + + void StopProfiler() { + base::Time stop_time = base::Time::Now(); + base::TimeDelta duration = stop_time - start_time_; + int micro_sec = static_cast<int>(duration.InMicroseconds()); + printf("\n<<< frame delivered : %d >>>", frame_count_); + printf("\n<<< time used(us) : %d >>>", micro_sec); + printf("\n<<< fps : %d >>>", frame_count_ * 1000000 / micro_sec); + // printf("\n<<< bitrate>>> : %I64d\n", bit_count_ * 1000000 / micro_sec); + printf("\n"); } scoped_refptr<media::OmxCodec> decoder_; MessageLoop message_loop_; - const char* filename_; + const char* input_filename_; + const char* output_filename_; const char* component_; - media::OmxCodec::Codec codec_; + media::OmxCodec::OmxMediaFormat input_format_; + media::OmxCodec::OmxMediaFormat output_format_; bool simulate_copy_; scoped_array<uint8> copy_buf_; int copy_buf_size_; - FILE* file_; + FILE *input_file_, *output_file_; bool stopped_; bool error_; + base::Time start_time_; + int frame_count_; + int bit_count_; }; +// Not intended to be used in production. +void NV21toI420(uint8* nv21, uint8* i420, int width, int height) { + memcpy(i420, nv21, width * height * sizeof(uint8)); + i420 += width * height; + nv21 += width * height; + uint8* u = i420; + uint8* v = i420 + width * height / 4; + + for (int i = 0; i < width * height / 4; ++i) { + *v++ = *nv21++; + *u++ = *nv21++; + } +} + +void NV21toYV12(uint8* nv21, uint8* yv12, int width, int height) { + memcpy(yv12, nv21, width * height * sizeof(uint8)); + yv12 += width * height; + nv21 += width * height; + uint8* v = yv12; + uint8* u = yv12 + width * height / 4; + + for (int i = 0; i < width * height / 4; ++i) { + *v++ = *nv21++; + *u++ = *nv21++; + } +} + +void I420toNV21(uint8* i420, uint8* nv21, int width, int height) { + memcpy(nv21, i420, width * height * sizeof(uint8)); + i420 += width * height; + nv21 += width * height; + uint8* u = i420; + uint8* v = i420 + width * height / 4; + + for (int i = 0; i < width * height / 4; ++i) { + *nv21++ = *v++; + *nv21++ = *u++; + } +} + +void YV12toNV21(uint8* yv12, uint8* nv21, int width, int height) { + memcpy(nv21, yv12, width * height * sizeof(uint8)); + yv12 += width * height; + nv21 += width * height; + uint8* v = yv12; + uint8* u = yv12 + width * height / 4; + + for (int i = 0; i < width * height / 4; ++i) { + *nv21++ = *v++; + *nv21++ = *u++; + } +} + int main(int argc, char** argv) { base::AtExitManager at_exit_manager; @@ -145,40 +247,98 @@ int main(int argc, char** argv) { const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); if (argc < 2) { - printf("Usage: omx_test --file=FILE --component=COMPONENT --codec=CODEC" - " [--copy]\n"); + printf("Usage: omx_test --input-file=FILE" + " --component=COMPONENT --codec=CODEC" + " [--output-file=FILE] [--enable-csc=FILE]" + " [--copy] [--measure-fps]\n"); printf(" COMPONENT: OpenMAX component name\n"); printf(" CODEC: h264/mpeg4/h263/vc1\n"); printf("\n"); printf("Optional Arguments\n"); - printf(" --copy Simulate a memcpy from the output of decoder.\n"); + printf(" --output-file Dump raw OMX output to file.\n"); + printf(" --enable-csc Dump the CSCed output to file.\n"); + printf(" --copy Simulate a memcpy from the output of decoder.\n"); + printf(" --measure-fps Measuring performance in fps\n"); return 1; } - std::string filename = cmd_line->GetSwitchValueASCII("file"); + std::string input_filename = cmd_line->GetSwitchValueASCII("input-file"); + std::string output_filename = cmd_line->GetSwitchValueASCII("output-file"); std::string component = cmd_line->GetSwitchValueASCII("component"); std::string codec = cmd_line->GetSwitchValueASCII("codec"); bool copy = cmd_line->HasSwitch("copy"); + bool measure_fps = cmd_line->HasSwitch("measure-fps"); + - media::OmxCodec::Codec codec_id = media::OmxCodec::kCodecNone; + media::OmxCodec::OmxMediaFormat input, output; + input.codec = media::OmxCodec::kCodecNone; if (codec == "h264") - codec_id = media::OmxCodec::kCodecH264; + input.codec = media::OmxCodec::kCodecH264; else if (codec == "mpeg4") - codec_id = media::OmxCodec::kCodecMpeg4; + input.codec = media::OmxCodec::kCodecMpeg4; else if (codec == "h263") - codec_id = media::OmxCodec::kCodecH263; + input.codec = media::OmxCodec::kCodecH263; else if (codec == "vc1") - codec_id = media::OmxCodec::kCodecVc1; + input.codec = media::OmxCodec::kCodecVc1; else { printf("Unknown codec.\n"); return 1; } + output.codec = media::OmxCodec::kCodecRaw; // Create a TestApp object and run the decoder. - TestApp test(filename.c_str(), component.c_str(), codec_id, copy); + TestApp test(input_filename.c_str(), + output_filename.c_str(), + component.c_str(), + input, + output, + copy); + + + if (measure_fps) + test.StartProfiler(); // This call will run the decoder until EOS is reached or an error // is encountered. test.Run(); + + if (measure_fps) + test.StopProfiler(); + + // Color space conversion. + if (!output_filename.empty()) { + std::string dumpyuv_name = cmd_line->GetSwitchValueASCII("enable-csc"); + if (!dumpyuv_name.empty()) { + // now assume the raw output is NV21; + // now assume decoder. + FILE* dump_raw = file_util::OpenFile(output_filename.c_str(), "rb"); + FILE* dump_yuv = file_util::OpenFile(dumpyuv_name.c_str(), "wb"); + if (!dump_raw || !dump_yuv) { + printf("Error - can't open file for color conversion %s\n", + dumpyuv_name.c_str()); + } else { + // TODO(jiesun): get rid of hard coded value when Startup() + // call back function is ready. + int width = 352; + int height = 288; + int frame_size = width * height * 3 / 2; // assume 4:2:0 chroma format. + scoped_array<uint8> in_buffer(new uint8[frame_size]); + scoped_array<uint8> out_buffer(new uint8[frame_size]); + while (true) { + int read; + read = fread(in_buffer.get(), sizeof(uint8), frame_size, dump_raw); + if (read != frame_size) + break; + NV21toI420(in_buffer.get(), out_buffer.get(), width, height); + fwrite(out_buffer.get(), sizeof(uint8), frame_size, dump_yuv); + } + } + if (dump_raw) + fclose(dump_raw); + if (dump_yuv) + fclose(dump_yuv); + } + } + return 0; } |