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