Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / media / cast / video_receiver / codecs / vp8 / vp8_decoder.cc
1 // Copyright 2013 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 "media/cast/video_receiver/codecs/vp8/vp8_decoder.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "media/base/video_frame.h"
11 #include "media/base/video_util.h"
12 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h"
13 #include "ui/gfx/size.h"
14
15 namespace media {
16 namespace cast {
17
18 void LogFrameDecodedEvent(CastEnvironment* const cast_environment,
19                           uint32 rtp_timestamp,
20                           uint32 frame_id) {
21   cast_environment->Logging()->InsertFrameEvent(
22       cast_environment->Clock()->NowTicks(),
23       kVideoFrameDecoded,
24       rtp_timestamp,
25       frame_id);
26 }
27
28 Vp8Decoder::Vp8Decoder(scoped_refptr<CastEnvironment> cast_environment)
29     : cast_environment_(cast_environment) {
30   // Make sure that we initialize the decoder from the correct thread.
31   cast_environment_->PostTask(
32       CastEnvironment::VIDEO_DECODER,
33       FROM_HERE,
34       base::Bind(&Vp8Decoder::InitDecoder, base::Unretained(this)));
35 }
36
37 Vp8Decoder::~Vp8Decoder() {
38   if (decoder_) {
39     vpx_codec_err_t ret = vpx_codec_destroy(decoder_.get());
40     CHECK_EQ(VPX_CODEC_OK, ret) << "vpx_codec_destroy() failed.";
41   }
42 }
43
44 void Vp8Decoder::InitDecoder() {
45   vpx_codec_dec_cfg_t cfg;
46   // Initializing to use one core.
47   cfg.threads = 1;
48   vpx_codec_flags_t flags = VPX_CODEC_USE_POSTPROC;
49
50   DCHECK(!decoder_);
51   decoder_.reset(new vpx_dec_ctx_t());
52   vpx_codec_err_t ret =
53       vpx_codec_dec_init(decoder_.get(), vpx_codec_vp8_dx(), &cfg, flags);
54   if (ret != VPX_CODEC_OK) {
55     DCHECK(false) << "vpx_codec_dec_init() failed.";
56     decoder_.reset();
57   }
58 }
59
60 bool Vp8Decoder::Decode(const transport::EncodedVideoFrame* encoded_frame,
61                         const base::TimeTicks render_time,
62                         const VideoFrameDecodedCallback& frame_decoded_cb) {
63   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::VIDEO_DECODER));
64   const int frame_id_int = static_cast<int>(encoded_frame->frame_id);
65   VLOG(1) << "VP8 decode frame:" << frame_id_int
66           << " sized:" << encoded_frame->data.size();
67
68   if (encoded_frame->data.empty())
69     return false;
70
71   vpx_codec_iter_t iter = NULL;
72   vpx_image_t* img;
73   const int real_time_decoding = 1;
74   if (vpx_codec_decode(
75           decoder_.get(),
76           reinterpret_cast<const uint8*>(encoded_frame->data.data()),
77           static_cast<unsigned int>(encoded_frame->data.size()),
78           0,
79           real_time_decoding)) {
80     VLOG(1) << "Failed to decode VP8 frame.";
81     return false;
82   }
83
84   img = vpx_codec_get_frame(decoder_.get(), &iter);
85   if (img == NULL) {
86     VLOG(1) << "Skip rendering VP8 frame:" << frame_id_int;
87     return false;
88   }
89
90   gfx::Size visible_size(img->d_w, img->d_h);
91   gfx::Size full_size(img->stride[VPX_PLANE_Y], img->d_h);
92   DCHECK(VideoFrame::IsValidConfig(
93       VideoFrame::I420, visible_size, gfx::Rect(visible_size), full_size));
94   // Temp timing setting - will sort out timing in a follow up cl.
95   scoped_refptr<VideoFrame> decoded_frame =
96       VideoFrame::CreateFrame(VideoFrame::I420,
97                               visible_size,
98                               gfx::Rect(visible_size),
99                               full_size,
100                               base::TimeDelta());
101
102   // Copy each plane individually (need to account for stride).
103   // TODO(mikhal): Eliminate copy once http://crbug.com/321856 is resolved.
104   CopyPlane(VideoFrame::kYPlane,
105             img->planes[VPX_PLANE_Y],
106             img->stride[VPX_PLANE_Y],
107             img->d_h,
108             decoded_frame.get());
109   CopyPlane(VideoFrame::kUPlane,
110             img->planes[VPX_PLANE_U],
111             img->stride[VPX_PLANE_U],
112             (img->d_h + 1) / 2,
113             decoded_frame.get());
114   CopyPlane(VideoFrame::kVPlane,
115             img->planes[VPX_PLANE_V],
116             img->stride[VPX_PLANE_V],
117             (img->d_h + 1) / 2,
118             decoded_frame.get());
119
120   VLOG(1) << "Decoded frame " << frame_id_int;
121
122   // Update logging from the main thread.
123   cast_environment_->PostTask(CastEnvironment::MAIN,
124                               FROM_HERE,
125                               base::Bind(LogFrameDecodedEvent,
126                                          cast_environment_,
127                                          encoded_frame->rtp_timestamp,
128                                          encoded_frame->frame_id));
129   // Frame decoded - return frame to the user via callback.
130   cast_environment_->PostTask(
131       CastEnvironment::MAIN,
132       FROM_HERE,
133       base::Bind(frame_decoded_cb, decoded_frame, render_time));
134
135   return true;
136 }
137
138 }  // namespace cast
139 }  // namespace media