summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-23 02:11:44 +0000
committerhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-23 02:11:44 +0000
commit71a418ccaceeea49dc8049b01a17a501e8070157 (patch)
tree28a9be5d04adb0d99e5acc28b037eda5933e8542 /media
parent13347d1506a5a5174bbe39099dc93041f1d0a497 (diff)
downloadchromium_src-71a418ccaceeea49dc8049b01a17a501e8070157.zip
chromium_src-71a418ccaceeea49dc8049b01a17a501e8070157.tar.gz
chromium_src-71a418ccaceeea49dc8049b01a17a501e8070157.tar.bz2
Use OpenMAX for video decoding in the media pipeline
This patch is to fix some issues when using OpenMAX video decoder in the media pipeline. It will enable player_x11 to decode using OpenMAX. This still requires some more work to enable Chrome to use OpenMAX for decoding. Review URL: http://codereview.chromium.org/549124 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36936 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/filters/decoder_base.h4
-rw-r--r--media/filters/omx_video_decode_engine.cc117
-rw-r--r--media/filters/omx_video_decode_engine.h21
-rw-r--r--media/omx/omx_codec.h2
-rw-r--r--media/tools/player_x11/player_x11.cc15
5 files changed, 111 insertions, 48 deletions
diff --git a/media/filters/decoder_base.h b/media/filters/decoder_base.h
index cc403bc..89bab8b 100644
--- a/media/filters/decoder_base.h
+++ b/media/filters/decoder_base.h
@@ -245,7 +245,9 @@ class DecoderBase : public Decoder {
// Note that it's possible for us to decode but not produce a frame, in
// which case |pending_reads_| will remain less than |read_queue_| so we
// need to schedule an additional read.
- DCHECK_LE(pending_reads_, read_queue_.size());
+ // TODO(hclam): Enable this line again to make sure we don't break the
+ // flow control. (BUG=32947)
+ // DCHECK_LE(pending_reads_, read_queue_.size());
while (pending_reads_ < read_queue_.size()) {
demuxer_stream_->Read(NewCallback(this, &DecoderBase::OnReadComplete));
++pending_reads_;
diff --git a/media/filters/omx_video_decode_engine.cc b/media/filters/omx_video_decode_engine.cc
index 89e687f..95209d7 100644
--- a/media/filters/omx_video_decode_engine.cc
+++ b/media/filters/omx_video_decode_engine.cc
@@ -2,8 +2,24 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This class is in interface to OmxCodec from the media playback
+// pipeline. It interacts with OmxCodec and the VideoDecoderImpl
+// in the media pipeline.
+//
+// THREADING SEMANTICS
+//
+// This class is created by VideoDecoderImpl and lives on the thread
+// that VideoDecoderImpl lives. This class is given the message loop
+// for the above thread. The same message loop is used to host
+// OmxCodec which is the interface to the actual OpenMAX hardware.
+// OmxCodec gurantees that all the callbacks are executed on the
+// hosting message loop. This essentially means that all methods in
+// this class are executed on the same thread as VideoDecoderImpl.
+// Because of that there's no need for locking anywhere.
+
#include "media/filters/omx_video_decode_engine.h"
+#include "base/message_loop.h"
#include "media/base/callback.h"
#include "media/filters/ffmpeg_common.h"
@@ -20,6 +36,8 @@ OmxVideoDecodeEngine::~OmxVideoDecodeEngine() {
}
void OmxVideoDecodeEngine::Initialize(AVStream* stream, Task* done_cb) {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+
AutoTaskRunner done_runner(done_cb);
omx_codec_ = new media::OmxCodec(message_loop_);
@@ -29,13 +47,15 @@ void OmxVideoDecodeEngine::Initialize(AVStream* stream, Task* done_cb) {
// TODO(ajwong): Extract magic formula to something based on output
// pixel format.
frame_bytes_ = (width_ * height_ * 3) / 2;
+ y_buffer_.reset(new uint8[width_ * height_]);
+ u_buffer_.reset(new uint8[width_ * height_ / 4]);
+ v_buffer_.reset(new uint8[width_ * height_ / 4]);
// TODO(ajwong): Find the right way to determine the Omx component name.
- OmxCodec::OmxMediaFormat input_format;
+ OmxCodec::OmxMediaFormat input_format, output_format;
memset(&input_format, 0, sizeof(input_format));
- input_format.codec = OmxCodec::kCodecH264;
- OmxCodec::OmxMediaFormat output_format;
memset(&output_format, 0, sizeof(output_format));
+ input_format.codec = OmxCodec::kCodecH264;
output_format.codec = OmxCodec::kCodecRaw;
omx_codec_->Setup(input_format, output_format);
omx_codec_->SetErrorCallback(
@@ -49,22 +69,29 @@ void OmxVideoDecodeEngine::Initialize(AVStream* stream, Task* done_cb) {
void OmxVideoDecodeEngine::OnFormatChange(
OmxCodec::OmxMediaFormat* input_format,
OmxCodec::OmxMediaFormat* output_format) {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
// TODO(jiesun): We should not need this for here, because width and height
// are already known from upper layer of the stack.
}
void OmxVideoDecodeEngine::OnHardwareError() {
- // TODO(ajwong): Threading?
+ DCHECK_EQ(message_loop_, MessageLoop::current());
state_ = kError;
}
+// This method assumes the input buffer contains exactly one frame or is an
+// end-of-stream buffer. The logic of this method and in OnReadComplete() is
+// based on this assumation.
+//
+// For every input buffer received here, we submit one read request to the
+// decoder. So when a read complete callback is received, a corresponding
+// decode request must exist.
void OmxVideoDecodeEngine::DecodeFrame(const Buffer& buffer,
AVFrame* yuv_frame,
bool* got_result,
Task* done_cb) {
- AutoTaskRunner done_runner(done_cb);
-
+ DCHECK_EQ(message_loop_, MessageLoop::current());
if (state_ != kNormal) {
return;
}
@@ -90,35 +117,21 @@ void OmxVideoDecodeEngine::DecodeFrame(const Buffer& buffer,
}
}
- omx_codec_->Read(NewCallback(this, &OmxVideoDecodeEngine::OnReadComplete));
-
- if (DecodedFrameAvailable()) {
- scoped_ptr<YuvFrame> frame(GetFrame());
+ // Enqueue the decode request and the associated buffer.
+ decode_request_queue_.push_back(
+ DecodeRequest(yuv_frame, got_result, done_cb));
- // TODO(ajwong): This is a memcpy(). Avoid this.
- // TODO(ajwong): This leaks memory. Fix by not using AVFrame.
- const size_t frame_pixels = width_ * height_;
- yuv_frame->data[0] = new uint8_t[frame_pixels];
- yuv_frame->data[1] = new uint8_t[frame_pixels / 4];
- yuv_frame->data[2] = new uint8_t[frame_pixels / 4];
- yuv_frame->linesize[0] = width_;
- yuv_frame->linesize[1] = width_ / 2;
- yuv_frame->linesize[2] = width_ / 2;
-
- memcpy(yuv_frame->data[0], frame->data, frame_pixels);
- memcpy(yuv_frame->data[1], frame->data + frame_pixels, frame_pixels / 4);
- memcpy(yuv_frame->data[2],
- frame->data + frame_pixels + frame_pixels/4,
- frame_pixels / 4);
- }
+ // Submit a read request to the decoder.
+ omx_codec_->Read(NewCallback(this, &OmxVideoDecodeEngine::OnReadComplete));
}
void OmxVideoDecodeEngine::OnFeedDone(InputBuffer* buffer) {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
// TODO(ajwong): Add a DoNothingCallback or similar.
}
void OmxVideoDecodeEngine::Flush(Task* done_cb) {
- AutoLock lock(lock_);
+ DCHECK_EQ(message_loop_, MessageLoop::current());
omx_codec_->Flush(TaskToCallbackAdapter::NewCallback(done_cb));
}
@@ -127,16 +140,52 @@ VideoSurface::Format OmxVideoDecodeEngine::GetSurfaceFormat() const {
}
void OmxVideoDecodeEngine::Stop(Callback0::Type* done_cb) {
- AutoLock lock(lock_);
+ DCHECK_EQ(message_loop_, MessageLoop::current());
omx_codec_->Stop(done_cb);
state_ = kStopped;
}
void OmxVideoDecodeEngine::OnReadComplete(uint8* buffer, int size) {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
if ((size_t)size != frame_bytes_) {
LOG(ERROR) << "Read completed with weird size: " << size;
}
+
+ // Merge the buffer into previous buffers.
MergeBytesFrameQueue(buffer, size);
+
+ // We assume that when we receive a read complete callback from
+ // OmxCodec there was a read request made.
+ CHECK(!decode_request_queue_.empty());
+ const DecodeRequest request = decode_request_queue_.front();
+ decode_request_queue_.pop_front();
+ *request.got_result = false;
+
+ // Detect if we have received a full decoded frame.
+ if (DecodedFrameAvailable()) {
+ // |frame| carries the decoded frame.
+ scoped_ptr<YuvFrame> frame(yuv_frame_queue_.front());
+ yuv_frame_queue_.pop_front();
+ *request.got_result = true;
+
+ // TODO(ajwong): This is a memcpy(). Avoid this.
+ // TODO(ajwong): This leaks memory. Fix by not using AVFrame.
+ const int pixels = width_ * height_;
+ request.frame->data[0] = y_buffer_.get();
+ request.frame->data[1] = u_buffer_.get();
+ request.frame->data[2] = v_buffer_.get();
+ request.frame->linesize[0] = width_;
+ request.frame->linesize[1] = width_ / 2;
+ request.frame->linesize[2] = width_ / 2;
+
+ memcpy(request.frame->data[0], frame->data, pixels);
+ memcpy(request.frame->data[1], frame->data + pixels,
+ pixels / 4);
+ memcpy(request.frame->data[2],
+ frame->data + pixels + pixels /4,
+ pixels / 4);
+ }
+ request.done_cb->Run();
}
bool OmxVideoDecodeEngine::IsFrameComplete(const YuvFrame* frame) {
@@ -144,13 +193,11 @@ bool OmxVideoDecodeEngine::IsFrameComplete(const YuvFrame* frame) {
}
bool OmxVideoDecodeEngine::DecodedFrameAvailable() {
- AutoLock lock(lock_);
return (!yuv_frame_queue_.empty() &&
IsFrameComplete(yuv_frame_queue_.front()));
}
void OmxVideoDecodeEngine::MergeBytesFrameQueue(uint8* buffer, int size) {
- AutoLock lock(lock_);
int amount_left = size;
// TODO(ajwong): Do the swizzle here instead of in DecodeFrame. This
@@ -167,14 +214,4 @@ void OmxVideoDecodeEngine::MergeBytesFrameQueue(uint8* buffer, int size) {
}
}
-OmxVideoDecodeEngine::YuvFrame* OmxVideoDecodeEngine::GetFrame() {
- AutoLock lock(lock_);
- if (yuv_frame_queue_.empty()) {
- return NULL;
- }
- YuvFrame* frame = yuv_frame_queue_.front();
- yuv_frame_queue_.pop_front();
- return frame;
-}
-
} // namespace media
diff --git a/media/filters/omx_video_decode_engine.h b/media/filters/omx_video_decode_engine.h
index fc3e4a1..29acf38 100644
--- a/media/filters/omx_video_decode_engine.h
+++ b/media/filters/omx_video_decode_engine.h
@@ -63,6 +63,20 @@ class OmxVideoDecodeEngine : public VideoDecodeEngine {
unsigned char* data;
};
+ // A struct to hold parameters of a decode request. Objects pointed by
+ // these parameters are owned by the caller.
+ struct DecodeRequest {
+ DecodeRequest(AVFrame* f, bool* b, Task* cb)
+ : frame(f),
+ got_result(b),
+ done_cb(cb) {
+ }
+
+ AVFrame* frame;
+ bool* got_result;
+ Task* done_cb;
+ };
+
virtual void OnFeedDone(InputBuffer* buffer);
virtual void OnHardwareError();
virtual void OnReadComplete(uint8* buffer, int size);
@@ -72,18 +86,21 @@ class OmxVideoDecodeEngine : public VideoDecodeEngine {
virtual bool DecodedFrameAvailable();
virtual void MergeBytesFrameQueue(uint8* buffer, int size);
virtual bool IsFrameComplete(const YuvFrame* frame);
- virtual YuvFrame* GetFrame();
- Lock lock_; // Locks the |state_| variable and the |yuv_frame_queue_|.
State state_;
size_t frame_bytes_;
size_t width_;
size_t height_;
+ scoped_array<uint8> y_buffer_;
+ scoped_array<uint8> u_buffer_;
+ scoped_array<uint8> v_buffer_;
+ // TODO(hclam): We should let OmxCodec handle this case.
bool has_fed_on_eos_; // Used to avoid sending an end of stream to
// OpenMax twice since OpenMax does not always
// handle this nicely.
std::list<YuvFrame*> yuv_frame_queue_;
+ std::list<DecodeRequest> decode_request_queue_;
scoped_refptr<media::OmxCodec> omx_codec_;
MessageLoop* message_loop_;
diff --git a/media/omx/omx_codec.h b/media/omx/omx_codec.h
index bb98a3d..e49fb4f 100644
--- a/media/omx/omx_codec.h
+++ b/media/omx/omx_codec.h
@@ -169,6 +169,8 @@ class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> {
};
};
+ // Initialize an OmxCodec object that runs on |message_loop|. It is
+ // guaranteed that callbacks are executed on this message loop.
explicit OmxCodec(MessageLoop* message_loop);
virtual ~OmxCodec();
diff --git a/media/tools/player_x11/player_x11.cc b/media/tools/player_x11/player_x11.cc
index 7cba68f..aa8194b 100644
--- a/media/tools/player_x11/player_x11.cc
+++ b/media/tools/player_x11/player_x11.cc
@@ -1,6 +1,6 @@
-// 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.
+// Copyright (c) 2009-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.
#include <iostream>
#include <signal.h>
@@ -106,8 +106,13 @@ void TerminateHandler(int signal) {
int main(int argc, char** argv) {
// Read arguments.
if (argc == 1) {
- std::cout << "Usage: " << argv[0] << " --file=FILE [--audio]"
- " [--alsa-device=DEVICE]" << std::endl;
+ std::cout << "Usage: " << argv[0] << " --file=FILE" << std::endl
+ << std::endl
+ << "Optional arguments:" << std::endl
+ << " [--enable-openmax]"
+ << " [--enable-h264-annexb-filter]"
+ << " [--audio]"
+ << " [--alsa-device=DEVICE]" << std::endl;
return 1;
}