• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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