Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(854)

Side by Side Diff: media/cast/video_receiver/video_decoder.cc

Issue 225023010: [Cast] Refactor/clean-up VideoReceiver to match AudioReceiver as closely as possible. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/cast/video_receiver/video_decoder.h" 5 #include "media/cast/video_receiver/video_decoder.h"
6 6
7 #include <stdint.h>
8
9 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/location.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h" 11 #include "base/stl_util.h"
12 #include "media/cast/video_receiver/codecs/vp8/vp8_decoder.h" 12 #include "media/base/video_util.h"
13 #include "media/cast/cast_defines.h"
14 #include "media/cast/cast_environment.h"
15 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide
16 // backwards compatibility for legacy applications using the library.
17 #define VPX_CODEC_DISABLE_COMPAT 1
18 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h"
19 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h"
20 #include "ui/gfx/size.h"
13 21
14 namespace media { 22 namespace media {
15 namespace cast { 23 namespace cast {
16 24
17 VideoDecoder::VideoDecoder(const VideoReceiverConfig& video_config, 25 // Base class that handles the common problem of detecting dropped frames, and
18 scoped_refptr<CastEnvironment> cast_environment) 26 // then invoking the Decode() method implemented by the subclasses to convert
19 : codec_(video_config.codec), vp8_decoder_() { 27 // the encoded payload data into a usable video frame.
28 class VideoDecoder::ImplBase
29 : public base::RefCountedThreadSafe<VideoDecoder::ImplBase> {
30 public:
31 ImplBase(const scoped_refptr<CastEnvironment>& cast_environment,
32 transport::VideoCodec codec)
33 : cast_environment_(cast_environment),
34 codec_(codec),
35 cast_initialization_status_(STATUS_VIDEO_UNINITIALIZED),
36 seen_first_frame_(false) {}
37
38 CastInitializationStatus InitializationResult() const {
39 return cast_initialization_status_;
40 }
41
42 void DecodeFrame(scoped_ptr<transport::EncodedVideoFrame> encoded_frame,
43 const DecodeFrameCallback& callback) {
44 DCHECK_EQ(cast_initialization_status_, STATUS_VIDEO_INITIALIZED);
45
46 if (encoded_frame->codec != codec_) {
47 NOTREACHED();
48 cast_environment_->PostTask(
49 CastEnvironment::MAIN,
50 FROM_HERE,
51 base::Bind(callback, scoped_refptr<VideoFrame>(NULL), false));
52 }
53
54 COMPILE_ASSERT(sizeof(encoded_frame->frame_id) == sizeof(last_frame_id_),
55 size_of_frame_id_types_do_not_match);
56 bool is_continuous = true;
57 if (seen_first_frame_) {
58 const uint32 frames_ahead = encoded_frame->frame_id - last_frame_id_;
59 if (frames_ahead > 1) {
60 RecoverBecauseFramesWereDropped();
61 is_continuous = false;
62 }
63 } else {
64 seen_first_frame_ = true;
65 }
66 last_frame_id_ = encoded_frame->frame_id;
67
68 const scoped_refptr<VideoFrame> decoded_frame = Decode(
69 reinterpret_cast<uint8*>(string_as_array(&encoded_frame->data)),
70 static_cast<int>(encoded_frame->data.size()));
71 cast_environment_->PostTask(
72 CastEnvironment::MAIN,
73 FROM_HERE,
74 base::Bind(callback, decoded_frame, is_continuous));
75 }
76
77 protected:
78 friend class base::RefCountedThreadSafe<ImplBase>;
79 virtual ~ImplBase() {}
80
81 virtual void RecoverBecauseFramesWereDropped() {}
82
83 // Note: Implementation of Decode() is allowed to mutate |data|.
84 virtual scoped_refptr<VideoFrame> Decode(uint8* data, int len) = 0;
85
86 const scoped_refptr<CastEnvironment> cast_environment_;
87 const transport::VideoCodec codec_;
88
89 // Subclass' ctor is expected to set this to STATUS_VIDEO_INITIALIZED.
90 CastInitializationStatus cast_initialization_status_;
91
92 private:
93 bool seen_first_frame_;
94 uint32 last_frame_id_;
95
96 DISALLOW_COPY_AND_ASSIGN(ImplBase);
97 };
98
99 class VideoDecoder::Vp8Impl : public VideoDecoder::ImplBase {
100 public:
101 explicit Vp8Impl(const scoped_refptr<CastEnvironment>& cast_environment)
102 : ImplBase(cast_environment, transport::kVp8) {
103 if (ImplBase::cast_initialization_status_ != STATUS_VIDEO_UNINITIALIZED)
104 return;
105
106 vpx_codec_dec_cfg_t cfg = {0};
107 // TODO(miu): Revisit this for typical multi-core desktop use case. This
108 // feels like it should be 4 or 8.
109 cfg.threads = 1;
110
111 DCHECK(vpx_codec_get_caps(vpx_codec_vp8_dx()) & VPX_CODEC_CAP_POSTPROC);
112 if (vpx_codec_dec_init(&context_,
113 vpx_codec_vp8_dx(),
114 &cfg,
115 VPX_CODEC_USE_POSTPROC) != VPX_CODEC_OK) {
116 ImplBase::cast_initialization_status_ =
117 STATUS_INVALID_VIDEO_CONFIGURATION;
118 return;
119 }
120 ImplBase::cast_initialization_status_ = STATUS_VIDEO_INITIALIZED;
121 }
122
123 private:
124 virtual ~Vp8Impl() {
125 if (ImplBase::cast_initialization_status_ == STATUS_VIDEO_INITIALIZED)
126 CHECK_EQ(VPX_CODEC_OK, vpx_codec_destroy(&context_));
127 }
128
129 virtual scoped_refptr<VideoFrame> Decode(uint8* data, int len) OVERRIDE {
130 if (len <= 0 || vpx_codec_decode(&context_,
131 data,
132 static_cast<unsigned int>(len),
133 NULL,
134 0) != VPX_CODEC_OK) {
135 return NULL;
136 }
137
138 vpx_codec_iter_t iter = NULL;
139 vpx_image_t* const image = vpx_codec_get_frame(&context_, &iter);
140 if (!image)
141 return NULL;
142 if (image->fmt != VPX_IMG_FMT_I420 && image->fmt != VPX_IMG_FMT_YV12) {
143 NOTREACHED();
144 return NULL;
145 }
146 DCHECK(vpx_codec_get_frame(&context_, &iter) == NULL)
147 << "Should have only decoded exactly one frame.";
148
149 const gfx::Size frame_size(image->d_w, image->d_h);
150 // Note: Timestamp for the VideoFrame will be set in VideoReceiver.
151 const scoped_refptr<VideoFrame> decoded_frame =
152 VideoFrame::CreateFrame(VideoFrame::YV12,
153 frame_size,
154 gfx::Rect(frame_size),
155 frame_size,
156 base::TimeDelta());
157 CopyYPlane(image->planes[VPX_PLANE_Y],
158 image->stride[VPX_PLANE_Y],
159 image->d_h,
160 decoded_frame);
161 CopyUPlane(image->planes[VPX_PLANE_U],
162 image->stride[VPX_PLANE_U],
163 (image->d_h + 1) / 2,
164 decoded_frame);
165 CopyVPlane(image->planes[VPX_PLANE_V],
166 image->stride[VPX_PLANE_V],
167 (image->d_h + 1) / 2,
168 decoded_frame);
169 return decoded_frame;
170 }
171
172 // VPX decoder context (i.e., an instantiation).
173 vpx_codec_ctx_t context_;
174
175 DISALLOW_COPY_AND_ASSIGN(Vp8Impl);
176 };
177
178 VideoDecoder::VideoDecoder(
179 const scoped_refptr<CastEnvironment>& cast_environment,
180 const VideoReceiverConfig& video_config)
181 : cast_environment_(cast_environment) {
20 switch (video_config.codec) { 182 switch (video_config.codec) {
21 case transport::kVp8: 183 case transport::kVp8:
22 vp8_decoder_.reset(new Vp8Decoder(cast_environment)); 184 impl_ = new Vp8Impl(cast_environment);
23 break; 185 break;
24 case transport::kH264: 186 case transport::kH264:
187 // TODO(miu): Need implementation.
25 NOTIMPLEMENTED(); 188 NOTIMPLEMENTED();
26 break; 189 break;
190 default:
191 NOTREACHED() << "Unknown or unspecified codec.";
192 break;
27 } 193 }
28 } 194 }
29 195
30 VideoDecoder::~VideoDecoder() {} 196 VideoDecoder::~VideoDecoder() {}
31 197
32 bool VideoDecoder::DecodeVideoFrame( 198 CastInitializationStatus VideoDecoder::InitializationResult() const {
33 const transport::EncodedVideoFrame* encoded_frame, 199 if (impl_)
34 const base::TimeTicks render_time, 200 return impl_->InitializationResult();
35 const VideoFrameDecodedCallback& frame_decoded_cb) { 201 return STATUS_UNSUPPORTED_VIDEO_CODEC;
36 DCHECK(encoded_frame->codec == codec_) << "Invalid codec";
37 DCHECK_GT(encoded_frame->data.size(), UINT64_C(0)) << "Empty video frame";
38 return vp8_decoder_->Decode(encoded_frame, render_time, frame_decoded_cb);
39 } 202 }
40 203
204 void VideoDecoder::DecodeFrame(
205 scoped_ptr<transport::EncodedVideoFrame> encoded_frame,
206 const DecodeFrameCallback& callback) {
207 DCHECK(encoded_frame.get());
208 DCHECK(!callback.is_null());
209 if (!impl_ || impl_->InitializationResult() != STATUS_VIDEO_INITIALIZED) {
210 callback.Run(make_scoped_refptr<VideoFrame>(NULL), false);
211 return;
212 }
213 cast_environment_->PostTask(CastEnvironment::VIDEO,
214 FROM_HERE,
215 base::Bind(&VideoDecoder::ImplBase::DecodeFrame,
216 impl_,
217 base::Passed(&encoded_frame),
218 callback));
219 }
220
41 } // namespace cast 221 } // namespace cast
42 } // namespace media 222 } // namespace media
OLDNEW
« no previous file with comments | « media/cast/video_receiver/video_decoder.h ('k') | media/cast/video_receiver/video_decoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698