Commit 68a3b425 authored by Dale Curtis's avatar Dale Curtis Committed by Commit Bot

Switch AomVideoDecoder to zero copy now that libaom fixes are in.

libaom has fixed all the framebuffer issues, so we should now be
able to use these. All tests pass and YouTube videos look good.
Seems only a minor memory savings ~2mb on a 480p clip.

This also resolves an issue with clipping of 64-bit timestamps
passed in as a void* (which might be 32-bit on some platforms).

BUG=867613,900302
TEST=existing tests all still pass.

Change-Id: I83af8ecd867e13741f27f5225316b62f31981562
Reviewed-on: https://chromium-review.googlesource.com/c/1316408
Commit-Queue: Dale Curtis <dalecurtis@chromium.org>
Reviewed-by: default avatarThomas Guilbert <tguilbert@chromium.org>
Cr-Commit-Position: refs/heads/master@{#605129}
parent de71694e
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "media/base/decoder_buffer.h" #include "media/base/decoder_buffer.h"
#include "media/base/media_log.h" #include "media/base/media_log.h"
#include "media/base/video_util.h" #include "media/base/video_util.h"
#include "media/filters/frame_buffer_pool.h"
#include "third_party/libyuv/include/libyuv/convert.h" #include "third_party/libyuv/include/libyuv/convert.h"
// Include libaom header files. // Include libaom header files.
...@@ -100,6 +101,28 @@ static void SetColorSpaceForFrame(const aom_image_t* img, ...@@ -100,6 +101,28 @@ static void SetColorSpaceForFrame(const aom_image_t* img,
frame->set_color_space(color_space.ToGfxColorSpace()); frame->set_color_space(color_space.ToGfxColorSpace());
} }
static int GetFrameBuffer(void* cb_priv,
size_t min_size,
aom_codec_frame_buffer* fb) {
DCHECK(cb_priv);
DCHECK(fb);
FrameBufferPool* pool = static_cast<FrameBufferPool*>(cb_priv);
fb->data = pool->GetFrameBuffer(min_size, &fb->priv);
fb->size = min_size;
return 0;
}
static int ReleaseFrameBuffer(void* cb_priv, aom_codec_frame_buffer* fb) {
DCHECK(cb_priv);
DCHECK(fb);
if (!fb->priv)
return -1;
FrameBufferPool* pool = static_cast<FrameBufferPool*>(cb_priv);
pool->ReleaseFrameBuffer(fb->priv);
return 0;
}
AomVideoDecoder::AomVideoDecoder(MediaLog* media_log) : media_log_(media_log) { AomVideoDecoder::AomVideoDecoder(MediaLog* media_log) : media_log_(media_log) {
DETACH_FROM_THREAD(thread_checker_); DETACH_FROM_THREAD(thread_checker_);
} }
...@@ -142,9 +165,6 @@ void AomVideoDecoder::Initialize( ...@@ -142,9 +165,6 @@ void AomVideoDecoder::Initialize(
// into uint8_t samples. // into uint8_t samples.
aom_config.allow_lowbitdepth = 1; aom_config.allow_lowbitdepth = 1;
// TODO(dalecurtis, tguilbert): Switch to zero-copy by specifying external
// frame buffer functions and use FrameBufferPool. https://crbug.com/867613
//
// TODO(dalecurtis, tguilbert): Move decoding off the media thread to the // TODO(dalecurtis, tguilbert): Move decoding off the media thread to the
// offload thread via OffloadingVideoDecoder. https://crbug.com/867613 // offload thread via OffloadingVideoDecoder. https://crbug.com/867613
...@@ -157,6 +177,18 @@ void AomVideoDecoder::Initialize( ...@@ -157,6 +177,18 @@ void AomVideoDecoder::Initialize(
return; return;
} }
// Setup codec for zero copy frames.
if (!memory_pool_)
memory_pool_ = new FrameBufferPool();
if (aom_codec_set_frame_buffer_functions(
context.get(), &GetFrameBuffer, &ReleaseFrameBuffer,
memory_pool_.get()) != AOM_CODEC_OK) {
DLOG(ERROR) << "Failed to configure external buffers. "
<< aom_codec_error(context.get());
bound_init_cb.Run(false);
return;
}
config_ = config; config_ = config;
state_ = DecoderState::kNormal; state_ = DecoderState::kNormal;
output_cb_ = BindToCurrentLoop(output_cb); output_cb_ = BindToCurrentLoop(output_cb);
...@@ -201,6 +233,7 @@ void AomVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer, ...@@ -201,6 +233,7 @@ void AomVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
void AomVideoDecoder::Reset(const base::Closure& reset_cb) { void AomVideoDecoder::Reset(const base::Closure& reset_cb) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
state_ = DecoderState::kNormal; state_ = DecoderState::kNormal;
timestamps_.clear();
base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE, reset_cb); base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE, reset_cb);
} }
...@@ -210,16 +243,20 @@ void AomVideoDecoder::CloseDecoder() { ...@@ -210,16 +243,20 @@ void AomVideoDecoder::CloseDecoder() {
return; return;
aom_codec_destroy(aom_decoder_.get()); aom_codec_destroy(aom_decoder_.get());
aom_decoder_.reset(); aom_decoder_.reset();
if (memory_pool_) {
memory_pool_->Shutdown();
memory_pool_ = nullptr;
}
} }
bool AomVideoDecoder::DecodeBuffer(const DecoderBuffer* buffer) { bool AomVideoDecoder::DecodeBuffer(const DecoderBuffer* buffer) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!buffer->end_of_stream()); DCHECK(!buffer->end_of_stream());
if (aom_codec_decode( timestamps_.push_back(buffer->timestamp());
aom_decoder_.get(), buffer->data(), buffer->data_size(), if (aom_codec_decode(aom_decoder_.get(), buffer->data(), buffer->data_size(),
reinterpret_cast<void*>(buffer->timestamp().InMicroseconds())) != nullptr) != AOM_CODEC_OK) {
AOM_CODEC_OK) {
const char* detail = aom_codec_error_detail(aom_decoder_.get()); const char* detail = aom_codec_error_detail(aom_decoder_.get());
MEDIA_LOG(ERROR, media_log_) MEDIA_LOG(ERROR, media_log_)
<< "aom_codec_decode() failed: " << aom_codec_error(aom_decoder_.get()) << "aom_codec_decode() failed: " << aom_codec_error(aom_decoder_.get())
...@@ -237,12 +274,13 @@ bool AomVideoDecoder::DecodeBuffer(const DecoderBuffer* buffer) { ...@@ -237,12 +274,13 @@ bool AomVideoDecoder::DecodeBuffer(const DecoderBuffer* buffer) {
return false; return false;
} }
frame->set_timestamp(base::TimeDelta::FromMicroseconds(
reinterpret_cast<int64_t>(img->user_priv)));
// TODO(dalecurtis): Is this true even for low resolutions? // TODO(dalecurtis): Is this true even for low resolutions?
frame->metadata()->SetBoolean(VideoFrameMetadata::POWER_EFFICIENT, false); frame->metadata()->SetBoolean(VideoFrameMetadata::POWER_EFFICIENT, false);
// Ensure the frame memory is returned to the MemoryPool upon discard.
frame->AddDestructionObserver(
memory_pool_->CreateFrameCallback(img->fb_priv));
SetColorSpaceForFrame(img, config_, frame.get()); SetColorSpaceForFrame(img, config_, frame.get());
output_cb_.Run(std::move(frame)); output_cb_.Run(std::move(frame));
} }
...@@ -258,22 +296,18 @@ scoped_refptr<VideoFrame> AomVideoDecoder::CopyImageToVideoFrame( ...@@ -258,22 +296,18 @@ scoped_refptr<VideoFrame> AomVideoDecoder::CopyImageToVideoFrame(
if (pixel_format == PIXEL_FORMAT_UNKNOWN) if (pixel_format == PIXEL_FORMAT_UNKNOWN)
return nullptr; return nullptr;
// Since we're making a copy, only copy the visible area. // Pull the expected timestamp from the front of the queue.
DCHECK(!timestamps_.empty());
const base::TimeDelta timestamp = timestamps_.front();
timestamps_.pop_front();
const gfx::Rect visible_rect(img->d_w, img->d_h); const gfx::Rect visible_rect(img->d_w, img->d_h);
auto frame = frame_pool_.CreateFrame( return VideoFrame::WrapExternalYuvData(
pixel_format, visible_rect.size(), visible_rect, pixel_format, visible_rect.size(), visible_rect,
GetNaturalSize(visible_rect, config_.GetPixelAspectRatio()), GetNaturalSize(visible_rect, config_.GetPixelAspectRatio()),
kNoTimestamp); img->stride[AOM_PLANE_Y], img->stride[AOM_PLANE_U],
if (!frame) img->stride[AOM_PLANE_V], img->planes[AOM_PLANE_Y],
return nullptr; img->planes[AOM_PLANE_U], img->planes[AOM_PLANE_V], timestamp);
for (int plane = 0; plane < 3; plane++) {
libyuv::CopyPlane(img->planes[plane], img->stride[plane],
frame->visible_data(plane), frame->stride(plane),
frame->row_bytes(plane), frame->rows(plane));
}
return frame;
} }
} // namespace media } // namespace media
...@@ -6,17 +6,18 @@ ...@@ -6,17 +6,18 @@
#define MEDIA_FILTERS_AOM_VIDEO_DECODER_H_ #define MEDIA_FILTERS_AOM_VIDEO_DECODER_H_
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/containers/circular_deque.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/threading/thread_checker.h" #include "base/threading/thread_checker.h"
#include "media/base/video_decoder.h" #include "media/base/video_decoder.h"
#include "media/base/video_decoder_config.h" #include "media/base/video_decoder_config.h"
#include "media/base/video_frame.h" #include "media/base/video_frame.h"
#include "media/base/video_frame_pool.h"
struct aom_codec_ctx; struct aom_codec_ctx;
struct aom_image; struct aom_image;
namespace media { namespace media {
class FrameBufferPool;
class MediaLog; class MediaLog;
// libaom video decoder wrapper. // libaom video decoder wrapper.
...@@ -73,7 +74,10 @@ class MEDIA_EXPORT AomVideoDecoder : public VideoDecoder { ...@@ -73,7 +74,10 @@ class MEDIA_EXPORT AomVideoDecoder : public VideoDecoder {
VideoDecoderConfig config_; VideoDecoderConfig config_;
// Pool used for memory efficiency when vending frames from the decoder. // Pool used for memory efficiency when vending frames from the decoder.
VideoFramePool frame_pool_; scoped_refptr<FrameBufferPool> memory_pool_;
// Timestamps are FIFO for libaom decoding.
base::circular_deque<base::TimeDelta> timestamps_;
// The allocated decoder; null before Initialize() and anytime after // The allocated decoder; null before Initialize() and anytime after
// CloseDecoder(). // CloseDecoder().
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment