OverlayRenderCb,
base::OnceClosure)> render_cb,
base::RepeatingCallback<void(scoped_refptr<TTvdDecodedFrame>)> release_cb,
+ MemoryUsageChangeCB memory_usage_cb,
const gpu::GpuDriverBugWorkarounds* workarounds) {
- scoped_refptr<TTvdDecodedFrame> result(new TTvdDecodedFrame(
- natural_size, std::move(command_buffer_helper),
- std::move(gpu_task_runner), std::move(release_cb), workarounds));
+ scoped_refptr<TTvdDecodedFrame> result(
+ new TTvdDecodedFrame(natural_size, std::move(command_buffer_helper),
+ std::move(gpu_task_runner), std::move(release_cb),
+ memory_usage_cb, workarounds));
TTvdDecodedFrame* raw_result = result.get();
raw_result->InitializeGpuPart(
allocate_memory, plane_collection,
scoped_refptr<CommandBufferHelper> command_buffer_helper,
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
base::RepeatingCallback<void(scoped_refptr<TTvdDecodedFrame>)> release_cb,
+ MemoryUsageChangeCB memory_usage_cb,
const gpu::GpuDriverBugWorkarounds* workarounds)
: picture_size_(natural_size),
command_buffer_helper_(std::move(command_buffer_helper)),
gpu_task_runner_(std::move(gpu_task_runner)),
release_cb_(std::move(release_cb)),
+ memory_usage_cb_(std::move(memory_usage_cb)),
workarounds_(workarounds) {
weak_this_ = weak_factory_.GetWeakPtr();
}
TTvdDecodedFrame::~TTvdDecodedFrame() {
+ if (pixmap_) {
+ const auto allocation_size =
+ VideoFrame::AllocationSize(PIXEL_FORMAT_NV12, picture_size_);
+ memory_usage_cb_.Run(-static_cast<int64_t>(allocation_size));
+ }
weak_factory_.InvalidateWeakPtrs();
gpu_task_runner_->DeleteSoon(FROM_HERE, std::move(frame_on_gpu_));
}
base::RepeatingCallback<void(base::WeakPtr<TTvdDecodedFrame>,
OverlayRenderCb,
base::OnceClosure)> render_cb) {
+ if (allocate_memory) {
+ const auto allocation_size =
+ VideoFrame::AllocationSize(PIXEL_FORMAT_NV12, picture_size_);
+ memory_usage_cb_.Run(static_cast<int64_t>(allocation_size));
+ }
gpu_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
return;
}
+ if (!pixmap_) {
+ const auto allocation_size =
+ VideoFrame::AllocationSize(PIXEL_FORMAT_NV12, picture_size_);
+ memory_usage_cb_.Run(static_cast<int64_t>(allocation_size));
+ }
pixmap_ = std::move(allocation_result);
}
using OverlayRenderCb =
base::RepeatingCallback<void(gfx::OverlayRenderData,
base::OnceCallback<void(bool)>)>;
+ using MemoryUsageChangeCB = base::RepeatingCallback<void(int64_t)>;
static void CreateAsync(
gfx::Size natural_size,
bool allocate_memory,
OverlayRenderCb,
base::OnceClosure)> render_cb,
base::RepeatingCallback<void(scoped_refptr<TTvdDecodedFrame>)> release_cb,
+ MemoryUsageChangeCB memory_usage_cb,
const gpu::GpuDriverBugWorkarounds* workarounds);
~TTvdDecodedFrame();
scoped_refptr<CommandBufferHelper> command_buffer_helper,
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
base::RepeatingCallback<void(scoped_refptr<TTvdDecodedFrame>)> release_cb,
+ MemoryUsageChangeCB memory_usage_cb,
const gpu::GpuDriverBugWorkarounds* workarounds);
void VideoFrameDestroyed(const gpu::SyncToken& sync_token);
std::unique_ptr<TTvdDecodedFrameOnGpu> frame_on_gpu_;
base::RepeatingCallback<void(scoped_refptr<TTvdDecodedFrame>)> release_cb_;
+ MemoryUsageChangeCB memory_usage_cb_;
+
const gpu::GpuDriverBugWorkarounds* workarounds_;
base::WeakPtr<TTvdDecodedFrame> weak_this_;
output_cb_.Run(frame);
}
+void TTvdVideoDecoder::OnTotalMemoryUsageReport(int64_t total_video_memory) {
+ last_reported_memory_usage_ = total_video_memory;
+ if (total_memory_usage_cb_) {
+ total_memory_usage_cb_.Run(last_reported_memory_usage_);
+ }
+}
+
void TTvdVideoDecoder::OnWaiting(WaitingReason reason) {
waiting_cb_.Run(reason);
}
decoder_->BindVideoResourceHelper(std::move(receiver), std::move(client));
}
+void TTvdVideoDecoder::SetTotalMemoryUsageCB(
+ TotalMemoryUsageCB memory_usage_cb) {
+ total_memory_usage_cb_ = memory_usage_cb;
+ if (last_reported_memory_usage_) {
+ total_memory_usage_cb_.Run(last_reported_memory_usage_);
+ }
+}
+
void TTvdVideoDecoder::ReleaseVideoFrame(
const base::UnguessableToken& release_token,
const gpu::SyncToken& release_sync_token) {
void OnVideoFrameDecoded(
const scoped_refptr<VideoFrame>& frame,
const base::UnguessableToken& release_token) override;
+ void OnTotalMemoryUsageReport(int64_t total_video_memory) override;
void OnWaiting(WaitingReason reason) override;
void BindVideoResourceHelper(
mojo::PendingAssociatedReceiver<mojom::VideoResourceHelper> receiver,
mojo::PendingAssociatedRemote<mojom::VideoResourceHelperClient> client);
+ using TotalMemoryUsageCB = base::RepeatingCallback<void(int64_t)>;
+ void SetTotalMemoryUsageCB(TotalMemoryUsageCB total_memory_usage_cb);
+
private:
void ReleaseVideoFrame(const base::UnguessableToken& release_token,
const gpu::SyncToken& release_sync_token);
base::flat_map<uint64_t, DecodeCB> pending_decodes_;
base::OnceClosure reset_cb_;
+ int64_t last_reported_memory_usage_ = 0;
+ TotalMemoryUsageCB total_memory_usage_cb_;
+
uint32_t writer_capacity_ = 0;
mojo::AssociatedReceiver<mojom::TTvdVideoDecoderClient> client_receiver_{
weak_factory_.GetWeakPtr()),
base::BindRepeating(&TTvdVideoDecoderImpl::ReleasePictureImpl,
weak_factory_.GetWeakPtr()),
+ base::BindRepeating(&TTvdVideoDecoderImpl::OnMemoryUsageChange,
+ weak_factory_.GetWeakPtr()),
&workarounds_);
event.Wait();
TIZEN_MEDIA_LOG(VERBOSE) << "Decoding results: " << decoding_results_.size()
weak_factory_.GetWeakPtr()),
base::BindRepeating(&TTvdVideoDecoderImpl::ReleasePictureImpl,
weak_factory_.GetWeakPtr()),
+ base::BindRepeating(&TTvdVideoDecoderImpl::OnMemoryUsageChange,
+ weak_factory_.GetWeakPtr()),
&workarounds_);
}
std::move(eos_cb_).Run(DecoderStatus::Codes::kOk);
}
+void TTvdVideoDecoderImpl::OnMemoryUsageChange(int64_t memory_delta) {
+ TIZEN_MEDIA_LOG(VERBOSE) << "Video memory delta: " << memory_delta;
+ total_memory_usage_ += memory_delta;
+ TIZEN_MEDIA_LOG(VERBOSE) << "Total memory usage: " << total_memory_usage_;
+ client_->OnTotalMemoryUsageReport(total_memory_usage_);
+}
+
void TTvdVideoDecoderImpl::UpdateConfigUsingBuffer(
const DecoderBuffer& buffer) {
UpdateConfig(&config_,
// in |decoding_requests_|.
void TriggerEos();
+ // Updates amount of memory usage by decoded frames currently hold by decoder.
+ void OnMemoryUsageChange(int64_t memory_delta);
+
void UpdateConfigUsingBuffer(const DecoderBuffer& buffer);
void UpdateConfigFromExtradata(const std::vector<uint8_t>& buffer);
WaitingCB waiting_cb_;
base::OnceClosure reset_cb_;
+ // Sum of all memory allocations for decoded video data used by decoder
+ // instance.
+ int64_t total_memory_usage_ = 0;
+
// Pool for not currently used TTvdDecodedFrame instances. Entries
// should be compatible with |output_mode_|.
std::deque<scoped_refptr<TTvdDecodedFrame>> ttvd_decoded_frame_pool_;
void TTvdVideoRenderer::OnDecoderChange(VideoDecoder* decoder) {
if (!decoder) {
+ last_reported_memory_usage_.reset();
return;
}
- if (video_resource_strategy_ !=
- VideoResourceStrategy::kHardwareOnlyAndPause ||
- !decoder->IsPlatformDecoder()) {
+ if (!decoder->IsPlatformDecoder()) {
return;
}
TTvdVideoDecoder* ttvd_video_decoder =
reinterpret_cast<TTvdVideoDecoder*>(decoder);
+
+ last_reported_memory_usage_ = 0;
+ ttvd_video_decoder->SetTotalMemoryUsageCB(base::BindRepeating(
+ &TTvdVideoRenderer::OnTotalMemoryUsageReport, base::Unretained(this)));
+
+ if (video_resource_strategy_ !=
+ VideoResourceStrategy::kHardwareOnlyAndPause) {
+ return;
+ }
+
video_resource_helper_.reset();
video_resource_helper_receiver_.reset();
ttvd_video_decoder->BindVideoResourceHelper(
stats_.video_frames_dropped, "id", player_id_);
}
- const size_t memory_usage = algorithm_->GetMemoryUsage();
+ // If we got data provided directly by hardware decoder, prefer it over
+ // estimation provided by algorithm. It counts real memory allocations
+ // and properly handles HW protected frames.
+ const size_t memory_usage = last_reported_memory_usage_
+ ? *last_reported_memory_usage_
+ : algorithm_->GetMemoryUsage();
stats_.video_memory_usage = memory_usage - stats_.video_memory_usage;
stats_.video_frame_duration_average = algorithm_->average_frame_duration();
OnStatisticsUpdate(stats_);
paint_first_frame_cb_.Cancel();
}
+void TTvdVideoRenderer::OnTotalMemoryUsageReport(int64_t total_video_memory) {
+ DCHECK(task_runner_->RunsTasksInCurrentSequence());
+ last_reported_memory_usage_ = total_video_memory;
+}
+
} // namespace media
// `painted_first_frame_` is false.
void PaintFirstFrame();
+ // Called by decoder to indicate new total memory used for held video frames.
+ void OnTotalMemoryUsageReport(int64_t total_video_memory);
+
scoped_refptr<base::SequencedTaskRunner> task_runner_;
// Sink which calls into TTvdVideoRenderer via Render() for video frames. Do
// Last FPS, if any, reported to the client.
absl::optional<int> last_reported_fps_;
+ // Last reported memory usage by Tizen TV video decoder.
+ // When set, it's prefered when sending pipeline statistics.
+ absl::optional<int64_t> last_reported_memory_usage_;
+
// Value saved from last call to SetLatencyHint(). Used to recompute buffering
// limits as framerate fluctuates.
absl::optional<base::TimeDelta> latency_hint_;
OnVideoFrameDecoded(VideoFrame frame,
mojo_base.mojom.UnguessableToken release_token);
+ // Provides information what is total memory used by decoder to hold video
+ // frames.
+ OnTotalMemoryUsageReport(int64 total_video_memory);
+
OnWaiting(WaitingReason reason);
};