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 "content/common/gpu/media/gpu_video_encode_accelerator.h"
6
7 #include "base/callback.h"
8 #include "base/logging.h"
9 #include "base/memory/shared_memory.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "build/build_config.h"
12 #include "content/common/gpu/gpu_channel.h"
13 #include "content/common/gpu/gpu_messages.h"
14 #include "ipc/ipc_message_macros.h"
15 #include "media/base/limits.h"
16 #include "media/base/video_frame.h"
17
18 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
19 #include "content/common/gpu/media/exynos_video_encode_accelerator.h"
20 #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
21 #include "content/common/gpu/media/android_video_encode_accelerator.h"
22 #endif
23
24 namespace content {
25
GpuVideoEncodeAccelerator(GpuChannel * gpu_channel,int32 route_id)26 GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator(GpuChannel* gpu_channel,
27 int32 route_id)
28 : weak_this_factory_(this),
29 channel_(gpu_channel),
30 route_id_(route_id),
31 input_format_(media::VideoFrame::UNKNOWN),
32 output_buffer_size_(0) {}
33
~GpuVideoEncodeAccelerator()34 GpuVideoEncodeAccelerator::~GpuVideoEncodeAccelerator() {
35 if (encoder_)
36 encoder_.release()->Destroy();
37 }
38
OnMessageReceived(const IPC::Message & message)39 bool GpuVideoEncodeAccelerator::OnMessageReceived(const IPC::Message& message) {
40 bool handled = true;
41 IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAccelerator, message)
42 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Initialize, OnInitialize)
43 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Encode, OnEncode)
44 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer,
45 OnUseOutputBitstreamBuffer)
46 IPC_MESSAGE_HANDLER(
47 AcceleratedVideoEncoderMsg_RequestEncodingParametersChange,
48 OnRequestEncodingParametersChange)
49 IPC_MESSAGE_UNHANDLED(handled = false)
50 IPC_END_MESSAGE_MAP()
51 return handled;
52 }
53
OnChannelError()54 void GpuVideoEncodeAccelerator::OnChannelError() {
55 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
56 if (channel_)
57 channel_ = NULL;
58 }
59
NotifyInitializeDone()60 void GpuVideoEncodeAccelerator::NotifyInitializeDone() {
61 Send(new AcceleratedVideoEncoderHostMsg_NotifyInitializeDone(route_id_));
62 }
63
RequireBitstreamBuffers(unsigned int input_count,const gfx::Size & input_coded_size,size_t output_buffer_size)64 void GpuVideoEncodeAccelerator::RequireBitstreamBuffers(
65 unsigned int input_count,
66 const gfx::Size& input_coded_size,
67 size_t output_buffer_size) {
68 Send(new AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers(
69 route_id_, input_count, input_coded_size, output_buffer_size));
70 input_coded_size_ = input_coded_size;
71 output_buffer_size_ = output_buffer_size;
72 }
73
BitstreamBufferReady(int32 bitstream_buffer_id,size_t payload_size,bool key_frame)74 void GpuVideoEncodeAccelerator::BitstreamBufferReady(int32 bitstream_buffer_id,
75 size_t payload_size,
76 bool key_frame) {
77 Send(new AcceleratedVideoEncoderHostMsg_BitstreamBufferReady(
78 route_id_, bitstream_buffer_id, payload_size, key_frame));
79 }
80
NotifyError(media::VideoEncodeAccelerator::Error error)81 void GpuVideoEncodeAccelerator::NotifyError(
82 media::VideoEncodeAccelerator::Error error) {
83 Send(new AcceleratedVideoEncoderHostMsg_NotifyError(route_id_, error));
84 }
85
86 // static
87 std::vector<media::VideoEncodeAccelerator::SupportedProfile>
GetSupportedProfiles()88 GpuVideoEncodeAccelerator::GetSupportedProfiles() {
89 std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles;
90
91 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
92 profiles = ExynosVideoEncodeAccelerator::GetSupportedProfiles();
93 #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
94 profiles = AndroidVideoEncodeAccelerator::GetSupportedProfiles();
95 #endif
96
97 // TODO(sheu): return platform-specific profiles.
98 return profiles;
99 }
100
CreateEncoder()101 void GpuVideoEncodeAccelerator::CreateEncoder() {
102 DCHECK(!encoder_);
103 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
104 encoder_.reset(new ExynosVideoEncodeAccelerator(this));
105 #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
106 encoder_.reset(new AndroidVideoEncodeAccelerator(this));
107 #endif
108 }
109
OnInitialize(media::VideoFrame::Format input_format,const gfx::Size & input_visible_size,media::VideoCodecProfile output_profile,uint32 initial_bitrate)110 void GpuVideoEncodeAccelerator::OnInitialize(
111 media::VideoFrame::Format input_format,
112 const gfx::Size& input_visible_size,
113 media::VideoCodecProfile output_profile,
114 uint32 initial_bitrate) {
115 DVLOG(2) << "GpuVideoEncodeAccelerator::OnInitialize(): "
116 "input_format=" << input_format
117 << ", input_visible_size=" << input_visible_size.ToString()
118 << ", output_profile=" << output_profile
119 << ", initial_bitrate=" << initial_bitrate;
120 DCHECK(!encoder_);
121
122 if (input_visible_size.width() > media::limits::kMaxDimension ||
123 input_visible_size.height() > media::limits::kMaxDimension ||
124 input_visible_size.GetArea() > media::limits::kMaxCanvas) {
125 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnInitialize(): "
126 "input_visible_size " << input_visible_size.ToString()
127 << " too large";
128 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
129 return;
130 }
131
132 CreateEncoder();
133 if (!encoder_) {
134 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnInitialize(): VEA creation "
135 "failed";
136 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
137 return;
138 }
139 encoder_->Initialize(
140 input_format, input_visible_size, output_profile, initial_bitrate);
141 input_format_ = input_format;
142 input_visible_size_ = input_visible_size;
143 }
144
OnEncode(int32 frame_id,base::SharedMemoryHandle buffer_handle,uint32 buffer_size,bool force_keyframe)145 void GpuVideoEncodeAccelerator::OnEncode(int32 frame_id,
146 base::SharedMemoryHandle buffer_handle,
147 uint32 buffer_size,
148 bool force_keyframe) {
149 DVLOG(3) << "GpuVideoEncodeAccelerator::OnEncode(): frame_id=" << frame_id
150 << ", buffer_size=" << buffer_size
151 << ", force_keyframe=" << force_keyframe;
152 if (!encoder_)
153 return;
154 if (frame_id < 0) {
155 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): invalid frame_id="
156 << frame_id;
157 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
158 return;
159 }
160
161 scoped_ptr<base::SharedMemory> shm(
162 new base::SharedMemory(buffer_handle, true));
163 if (!shm->Map(buffer_size)) {
164 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): "
165 "could not map frame_id=" << frame_id;
166 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
167 return;
168 }
169
170 uint8* shm_memory = reinterpret_cast<uint8*>(shm->memory());
171 scoped_refptr<media::VideoFrame> frame =
172 media::VideoFrame::WrapExternalPackedMemory(
173 input_format_,
174 input_coded_size_,
175 gfx::Rect(input_visible_size_),
176 input_visible_size_,
177 shm_memory,
178 buffer_size,
179 buffer_handle,
180 base::TimeDelta(),
181 // It's turtles all the way down...
182 base::Bind(base::IgnoreResult(&base::MessageLoopProxy::PostTask),
183 base::MessageLoopProxy::current(),
184 FROM_HERE,
185 base::Bind(&GpuVideoEncodeAccelerator::EncodeFrameFinished,
186 weak_this_factory_.GetWeakPtr(),
187 frame_id,
188 base::Passed(&shm))));
189
190 if (!frame) {
191 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): "
192 "could not create VideoFrame for frame_id=" << frame_id;
193 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
194 return;
195 }
196
197 encoder_->Encode(frame, force_keyframe);
198 }
199
OnUseOutputBitstreamBuffer(int32 buffer_id,base::SharedMemoryHandle buffer_handle,uint32 buffer_size)200 void GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(
201 int32 buffer_id,
202 base::SharedMemoryHandle buffer_handle,
203 uint32 buffer_size) {
204 DVLOG(3) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
205 "buffer_id=" << buffer_id
206 << ", buffer_size=" << buffer_size;
207 if (!encoder_)
208 return;
209 if (buffer_id < 0) {
210 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
211 "invalid buffer_id=" << buffer_id;
212 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
213 return;
214 }
215 if (buffer_size < output_buffer_size_) {
216 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
217 "buffer too small for buffer_id=" << buffer_id;
218 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
219 return;
220 }
221 encoder_->UseOutputBitstreamBuffer(
222 media::BitstreamBuffer(buffer_id, buffer_handle, buffer_size));
223 }
224
OnRequestEncodingParametersChange(uint32 bitrate,uint32 framerate)225 void GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(
226 uint32 bitrate,
227 uint32 framerate) {
228 DVLOG(2) << "GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(): "
229 "bitrate=" << bitrate
230 << ", framerate=" << framerate;
231 if (!encoder_)
232 return;
233 encoder_->RequestEncodingParametersChange(bitrate, framerate);
234 }
235
EncodeFrameFinished(int32 frame_id,scoped_ptr<base::SharedMemory> shm)236 void GpuVideoEncodeAccelerator::EncodeFrameFinished(
237 int32 frame_id,
238 scoped_ptr<base::SharedMemory> shm) {
239 Send(new AcceleratedVideoEncoderHostMsg_NotifyInputDone(route_id_, frame_id));
240 // Just let shm fall out of scope.
241 }
242
Send(IPC::Message * message)243 void GpuVideoEncodeAccelerator::Send(IPC::Message* message) {
244 if (!channel_) {
245 DLOG(ERROR) << "GpuVideoEncodeAccelerator::Send(): no channel";
246 delete message;
247 return;
248 } else if (!channel_->Send(message)) {
249 DLOG(ERROR) << "GpuVideoEncodeAccelerator::Send(): sending failed: "
250 "message->type()=" << message->type();
251 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
252 return;
253 }
254 }
255
256 } // namespace content
257