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.
5 #include "media/cast/video_receiver/codecs/vp8/vp8_decoder.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"
18 void LogFrameDecodedEvent(CastEnvironment
* const cast_environment
,
21 cast_environment
->Logging()->InsertFrameEvent(
22 cast_environment
->Clock()->NowTicks(),
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
,
34 base::Bind(&Vp8Decoder::InitDecoder
, base::Unretained(this)));
37 Vp8Decoder::~Vp8Decoder() {
39 vpx_codec_err_t ret
= vpx_codec_destroy(decoder_
.get());
40 CHECK_EQ(VPX_CODEC_OK
, ret
) << "vpx_codec_destroy() failed.";
44 void Vp8Decoder::InitDecoder() {
45 vpx_codec_dec_cfg_t cfg
;
46 // Initializing to use one core.
48 vpx_codec_flags_t flags
= VPX_CODEC_USE_POSTPROC
;
51 decoder_
.reset(new vpx_dec_ctx_t());
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.";
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();
68 if (encoded_frame
->data
.empty())
71 vpx_codec_iter_t iter
= NULL
;
73 const int real_time_decoding
= 1;
76 reinterpret_cast<const uint8
*>(encoded_frame
->data
.data()),
77 static_cast<unsigned int>(encoded_frame
->data
.size()),
79 real_time_decoding
)) {
80 VLOG(1) << "Failed to decode VP8 frame.";
84 img
= vpx_codec_get_frame(decoder_
.get(), &iter
);
86 VLOG(1) << "Skip rendering VP8 frame:" << frame_id_int
;
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
,
98 gfx::Rect(visible_size
),
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
],
108 decoded_frame
.get());
109 CopyPlane(VideoFrame::kUPlane
,
110 img
->planes
[VPX_PLANE_U
],
111 img
->stride
[VPX_PLANE_U
],
113 decoded_frame
.get());
114 CopyPlane(VideoFrame::kVPlane
,
115 img
->planes
[VPX_PLANE_V
],
116 img
->stride
[VPX_PLANE_V
],
118 decoded_frame
.get());
120 VLOG(1) << "Decoded frame " << frame_id_int
;
122 // Update logging from the main thread.
123 cast_environment_
->PostTask(CastEnvironment::MAIN
,
125 base::Bind(LogFrameDecodedEvent
,
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
,
133 base::Bind(frame_decoded_cb
, decoded_frame
, render_time
));