1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chromecast/media/cma/ipc_streamer/coded_frame_provider_host.h"
6
7#include "base/bind.h"
8#include "base/callback_helpers.h"
9#include "chromecast/media/cma/base/decoder_buffer_base.h"
10#include "chromecast/media/cma/ipc/media_message.h"
11#include "chromecast/media/cma/ipc/media_message_fifo.h"
12#include "chromecast/media/cma/ipc/media_message_type.h"
13#include "chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.h"
14#include "chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.h"
15#include "chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.h"
16#include "media/base/buffers.h"
17#include "media/base/decrypt_config.h"
18
19namespace chromecast {
20namespace media {
21
22CodedFrameProviderHost::CodedFrameProviderHost(
23    scoped_ptr<MediaMessageFifo> media_message_fifo)
24  : fifo_(media_message_fifo.Pass()),
25    weak_factory_(this),
26    weak_this_(weak_factory_.GetWeakPtr()) {
27  thread_checker_.DetachFromThread();
28}
29
30CodedFrameProviderHost::~CodedFrameProviderHost() {
31  DCHECK(thread_checker_.CalledOnValidThread());
32}
33
34void CodedFrameProviderHost::Read(const ReadCB& read_cb) {
35  DCHECK(thread_checker_.CalledOnValidThread());
36
37  // Cannot be called if there is already a pending read.
38  DCHECK(read_cb_.is_null());
39  read_cb_ = read_cb;
40
41  ReadMessages();
42}
43
44void CodedFrameProviderHost::Flush(const base::Closure& flush_cb) {
45  DCHECK(thread_checker_.CalledOnValidThread());
46  audio_config_ = ::media::AudioDecoderConfig();
47  video_config_ = ::media::VideoDecoderConfig();
48  read_cb_.Reset();
49  fifo_->Flush();
50  flush_cb.Run();
51}
52
53void CodedFrameProviderHost::OnFifoWriteEvent() {
54  DCHECK(thread_checker_.CalledOnValidThread());
55  ReadMessages();
56}
57
58base::Closure CodedFrameProviderHost::GetFifoWriteEventCb() {
59  return base::Bind(&CodedFrameProviderHost::OnFifoWriteEvent, weak_this_);
60}
61
62void CodedFrameProviderHost::ReadMessages() {
63  // Read messages until a frame is provided (i.e. not just the audio/video
64  // configurations).
65  while (!read_cb_.is_null()) {
66    scoped_ptr<MediaMessage> msg(fifo_->Pop());
67    if (!msg)
68      break;
69
70    if (msg->type() == PaddingMediaMsg) {
71      // Ignore the message.
72    } else if (msg->type() == AudioConfigMediaMsg) {
73      audio_config_ = AudioDecoderConfigMarshaller::Read(msg.get());
74    } else if (msg->type() == VideoConfigMediaMsg) {
75      video_config_ = VideoDecoderConfigMarshaller::Read(msg.get());
76    } else if (msg->type() == FrameMediaMsg) {
77      scoped_refptr<DecoderBufferBase> buffer =
78          DecoderBufferBaseMarshaller::Read(msg.Pass());
79      base::ResetAndReturn(&read_cb_).Run(
80          buffer, audio_config_, video_config_);
81      audio_config_ = ::media::AudioDecoderConfig();
82      video_config_ = ::media::VideoDecoderConfig();
83    } else {
84      // Receiving an unexpected message.
85      // Possible use case (except software bugs): the renderer process has
86      // been compromised and an invalid message value has been written to
87      // the fifo. Crash the browser process in this case to avoid further
88      // security implications (so do not use NOTREACHED which crashes only
89      // in debug builds).
90      LOG(FATAL) << "Unknown media message";
91    }
92  }
93}
94
95}  // namespace media
96}  // namespace chromecast
97