OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 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/logging.h" | |
8 #include "base/memory/shared_memory.h" | |
9 #include "content/common/gpu/gpu_channel.h" | |
10 #include "content/common/gpu/gpu_messages.h" | |
11 #include "ipc/ipc_message_macros.h" | |
12 #include "media/base/video_frame.h" | |
13 | |
14 namespace content { | |
15 | |
16 GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator(GpuChannel* gpu_channel, | |
17 int32 route_id) | |
18 : channel_(gpu_channel), | |
19 route_id_(route_id), | |
20 input_format_(media::VideoFrame::INVALID), | |
21 output_buffer_size_(0) {} | |
22 | |
23 GpuVideoEncodeAccelerator::~GpuVideoEncodeAccelerator() { | |
24 if (encoder_) | |
25 encoder_.release()->Destroy(); | |
26 } | |
27 | |
28 bool GpuVideoEncodeAccelerator::OnMessageReceived(const IPC::Message& message) { | |
29 bool handled = true; | |
30 IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAccelerator, message) | |
31 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Initialize, OnInitialize) | |
32 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Encode, OnEncode) | |
33 IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer, | |
34 OnUseOutputBitstreamBuffer) | |
35 IPC_MESSAGE_HANDLER( | |
36 AcceleratedVideoEncoderMsg_RequestEncodingParametersChange, | |
37 OnRequestEncodingParametersChange) | |
38 IPC_MESSAGE_UNHANDLED(handled = false) | |
39 IPC_END_MESSAGE_MAP() | |
40 return handled; | |
41 } | |
42 | |
43 void GpuVideoEncodeAccelerator::OnChannelError() { | |
44 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | |
45 if (channel_) | |
46 channel_ = NULL; | |
47 } | |
48 | |
49 void GpuVideoEncodeAccelerator::NotifyInitializeDone() { | |
50 Send(new AcceleratedVideoEncoderHostMsg_NotifyInitializeDone(route_id_)); | |
51 } | |
52 | |
53 void GpuVideoEncodeAccelerator::RequireBitstreamBuffers( | |
54 int input_count, | |
55 const gfx::Size& input_coded_size, | |
56 size_t output_buffer_size) { | |
57 Send(new AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers( | |
58 route_id_, input_count, input_coded_size, output_buffer_size)); | |
59 input_coded_size_ = input_coded_size; | |
60 output_buffer_size_ = output_buffer_size; | |
61 } | |
62 | |
63 void GpuVideoEncodeAccelerator::BitstreamBufferReady(int32 bitstream_buffer_id, | |
64 size_t payload_size, | |
65 bool key_frame) { | |
66 Send(new AcceleratedVideoEncoderHostMsg_BitstreamBufferReady( | |
67 route_id_, bitstream_buffer_id, payload_size, key_frame)); | |
68 } | |
69 | |
70 void GpuVideoEncodeAccelerator::NotifyError( | |
71 media::VideoEncodeAccelerator::Error error) { | |
72 Send(new AcceleratedVideoEncoderHostMsg_NotifyError(route_id_, error)); | |
73 } | |
74 | |
75 // static | |
76 std::vector<media::VideoEncodeAccelerator::SupportedProfile> | |
77 GpuVideoEncodeAccelerator::GetSupportedProfiles() { | |
78 std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles; | |
79 | |
80 // TODO(sheu): return platform-specific profiles. | |
81 return profiles; | |
82 } | |
83 | |
84 void GpuVideoEncodeAccelerator::CreateEncoder() { | |
85 // TODO(sheu): actual create the encoder. | |
86 } | |
87 | |
88 void GpuVideoEncodeAccelerator::OnInitialize( | |
89 media::VideoFrame::Format input_format, | |
90 const gfx::Size& input_visible_size, | |
91 media::VideoCodecProfile output_profile, | |
92 int32 initial_bitrate) { | |
93 DVLOG(2) << "GpuVideoEncodeAccelerator::OnInitialize(): " | |
94 "input_format=" << input_format | |
95 << ", input_visible_size=" << input_visible_size.ToString() | |
96 << ", output_profile=" << output_profile | |
97 << ", initial_bitrate=" << initial_bitrate; | |
98 DCHECK(!encoder_); | |
99 | |
100 CreateEncoder(); | |
101 if (!encoder_) { | |
102 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnInitialize(): VEA creation " | |
103 "failed"; | |
104 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | |
105 return; | |
106 } | |
107 encoder_->Initialize( | |
108 input_format, input_visible_size, output_profile, initial_bitrate); | |
109 input_format_ = input_format; | |
110 input_visible_size_ = input_visible_size; | |
111 } | |
112 | |
113 void GpuVideoEncodeAccelerator::OnEncode(int32 frame_id, | |
114 base::SharedMemoryHandle buffer_handle, | |
115 uint32 buffer_size, | |
116 bool force_keyframe) { | |
117 DVLOG(3) << "GpuVideoEncodeAccelerator::OnEncode(): frame_id=" << frame_id | |
118 << ", buffer_size=" << buffer_size | |
119 << ", force_keyframe=" << force_keyframe; | |
120 if (!encoder_) | |
121 return; | |
122 if (frame_id < 0) { | |
123 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): invalid frame_id=" | |
124 << frame_id; | |
125 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | |
126 return; | |
127 } | |
128 | |
129 scoped_ptr<base::SharedMemory> shm( | |
130 new base::SharedMemory(buffer_handle, true)); | |
131 if (!shm->Map(buffer_size)) { | |
132 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): " | |
133 "could not map frame_id=" << frame_id; | |
134 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | |
135 return; | |
136 } | |
137 | |
138 scoped_refptr<media::VideoFrame> frame; | |
139 switch (input_format_) { | |
140 case media::VideoFrame::I420: { | |
141 if (buffer_size < | |
142 static_cast<size_t>(input_coded_size_.GetArea() * 3 / 2)) { | |
143 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): " | |
144 "buffer too small for frame_id=" << frame_id; | |
145 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | |
146 return; | |
147 } | |
148 uint8* data = reinterpret_cast<uint8*>(shm->memory()); | |
149 frame = media::VideoFrame::WrapExternalYuvData( | |
150 media::VideoFrame::I420, | |
151 input_coded_size_, | |
152 gfx::Rect(input_visible_size_), | |
153 input_visible_size_, | |
154 input_coded_size_.width(), | |
155 input_coded_size_.width() / 2, | |
156 input_coded_size_.width() / 2, | |
157 data, | |
158 data + input_coded_size_.GetArea(), | |
159 data + (input_coded_size_.GetArea() * 5 / 4), | |
160 base::TimeDelta(), | |
161 buffer_handle, | |
162 base::Bind(&GpuVideoEncodeAccelerator::EncodeFrameFinished, | |
163 base::Unretained(this), | |
piman
2013/08/09 04:04:58
what makes this Unretained safe?
sheu
2013/08/09 08:26:41
That's an interesting question, I guess. I was as
piman
2013/08/12 21:43:40
Why do you then need the extra PostTask?
sheu
2013/08/12 21:58:18
The VideoFrame destructor will call the callback,
piman
2013/08/13 01:00:04
Ok.
| |
164 frame_id, | |
165 base::Passed(&shm))); | |
166 break; | |
167 } | |
168 default: | |
169 NOTREACHED(); | |
piman
2013/08/09 04:04:58
This comes from the untrusted renderer, so it can
sheu
2013/08/09 08:26:41
Right, if it's reached, we proceed to return an er
piman
2013/08/12 21:43:40
It can give a false sense of security, which, for
sheu
2013/08/12 21:58:18
Sure -- in any case though this has been pulled in
| |
170 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | |
171 return; | |
172 } | |
173 | |
174 encoder_->Encode(frame, force_keyframe); | |
175 } | |
176 | |
177 void GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer( | |
178 int32 buffer_id, | |
179 base::SharedMemoryHandle buffer_handle, | |
180 uint32 buffer_size) { | |
181 DVLOG(3) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): " | |
182 "buffer_id=" << buffer_id | |
183 << ", buffer_size=" << buffer_size; | |
184 if (!encoder_) | |
185 return; | |
186 if (buffer_id < 0) { | |
187 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): " | |
188 "invalid buffer_id=" << buffer_id; | |
189 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | |
190 return; | |
191 } | |
192 if (buffer_size < output_buffer_size_) { | |
193 DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): " | |
194 "buffer too small for buffer_id=" << buffer_id; | |
195 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | |
196 return; | |
197 } | |
198 encoder_->UseOutputBitstreamBuffer( | |
199 media::BitstreamBuffer(buffer_id, buffer_handle, buffer_size)); | |
piman
2013/08/09 04:04:58
what happens if buffer_handle is invalid, or doesn
sheu
2013/08/09 08:26:41
If the buffer handle is invalid, mapping it will f
piman
2013/08/12 21:43:40
We want to make sure this is properly communicated
sheu
2013/08/12 21:58:18
Right, but how do we know the buffer size? It's g
piman
2013/08/13 01:00:04
You have no way of knowing it (well, fstat would o
sheu
2013/08/13 01:07:08
Right, and the solution adopted elsewhere (i.e. th
| |
200 } | |
201 | |
202 void GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange( | |
203 int32 bitrate, | |
204 uint32 framerate) { | |
205 DVLOG(2) << "GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(): " | |
206 "bitrate=" << bitrate | |
207 << ", framerate=" << framerate; | |
208 if (!encoder_) | |
209 return; | |
210 encoder_->RequestEncodingParametersChange(bitrate, framerate); | |
211 } | |
212 | |
213 void GpuVideoEncodeAccelerator::EncodeFrameFinished( | |
214 int32 frame_id, | |
215 scoped_ptr<base::SharedMemory> shm) { | |
216 Send(new AcceleratedVideoEncoderHostMsg_NotifyInputDone(route_id_, frame_id)); | |
217 // Just let shm fall out of scope. | |
218 } | |
219 | |
220 void GpuVideoEncodeAccelerator::Send(IPC::Message* message) { | |
221 if (!channel_) { | |
222 DLOG(ERROR) << "GpuVideoEncodeAccelerator::Send(): no channel"; | |
223 delete message; | |
224 return; | |
225 } else if (!channel_->Send(message)) { | |
226 DLOG(ERROR) << "GpuVideoEncodeAccelerator::Send(): sending failed: " | |
227 "message->type()=" << message->type(); | |
228 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | |
229 return; | |
230 } | |
231 } | |
232 | |
233 } // namespace content | |
OLD | NEW |