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

Side by Side Diff: content/common/gpu/media/vaapi_jpeg_decode_accelerator.cc

Issue 1124423008: MJPEG acceleration for video capture using VAAPI, the GPU and IPC part (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@mjpeg-1-media
Patch Set: Created 5 years, 6 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
OLDNEW
(Empty)
1 // Copyright 2015 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/vaapi_jpeg_decode_accelerator.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "base/trace_event/trace_event.h"
11 #include "content/common/gpu/gpu_channel.h"
12 #include "content/common/gpu/media/vaapi_picture.h"
13 #include "media/base/video_frame.h"
14 #include "media/filters/jpeg_parser.h"
15
16 namespace content {
17
18 namespace {
19 static void ReportVaapiError() {
20 // TODO(kcwu) report error to UMA
21 }
22 } // namespace
23
24 VaapiJpegDecodeAccelerator::DecodeRequest::DecodeRequest(
25 const media::BitstreamBuffer& bitstream_buffer,
26 const scoped_refptr<media::VideoFrame>& video_frame)
27 : bitstream_buffer(bitstream_buffer), video_frame(video_frame) {
28 }
29
30 VaapiJpegDecodeAccelerator::DecodeRequest::~DecodeRequest() {
31 }
32
33 void VaapiJpegDecodeAccelerator::NotifyError(int32_t bitstream_buffer_id,
34 Error error) {
35 DCHECK(task_runner_->BelongsToCurrentThread());
36 DLOG(ERROR) << "Notifying of error " << error;
37 DCHECK(client_);
38 client_->NotifyError(bitstream_buffer_id, error);
39 }
40
41 void VaapiJpegDecodeAccelerator::NotifyErrorFromDecoderThread(
42 int32_t bitstream_buffer_id,
43 Error error) {
44 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
45 task_runner_->PostTask(FROM_HERE,
46 base::Bind(&VaapiJpegDecodeAccelerator::NotifyError,
47 weak_this_, bitstream_buffer_id, error));
48 }
49
50 void VaapiJpegDecodeAccelerator::VideoFrameReady(int32_t bitstream_buffer_id) {
51 DCHECK(task_runner_->BelongsToCurrentThread());
52 client_->VideoFrameReady(bitstream_buffer_id);
53 }
54
55 VaapiJpegDecodeAccelerator::VaapiJpegDecodeAccelerator(
56 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
57 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
58 io_task_runner_(io_task_runner),
59 decoder_thread_("VaapiJpegDecoderThread"),
60 va_surface_id_(VA_INVALID_SURFACE),
61 weak_this_factory_(this) {
62 weak_this_ = weak_this_factory_.GetWeakPtr();
63 }
64
65 VaapiJpegDecodeAccelerator::~VaapiJpegDecodeAccelerator() {
66 DCHECK(task_runner_->BelongsToCurrentThread());
67 DVLOG(1) << "Destroying VaapiJpegDecodeAccelerator";
68
69 weak_this_factory_.InvalidateWeakPtrs();
70 decoder_thread_.Stop();
71 }
72
73 bool VaapiJpegDecodeAccelerator::Initialize(Client* client) {
74 DCHECK(task_runner_->BelongsToCurrentThread());
75
76 client_ = client;
77
78 vaapi_wrapper_ =
79 VaapiWrapper::Create(VaapiWrapper::kDecode, VAProfileJPEGBaseline,
80 base::Bind(&ReportVaapiError));
81
82 if (!vaapi_wrapper_.get()) {
83 DLOG(ERROR) << "Failed initializing VAAPI";
84 return false;
85 }
86
87 if (!decoder_thread_.Start()) {
88 DLOG(ERROR) << "Failed to start decoding thread.";
89 return false;
90 }
91 decoder_task_runner_ = decoder_thread_.task_runner();
92
93 return true;
94 }
95
96 bool VaapiJpegDecodeAccelerator::OutputPicture(
97 VASurfaceID va_surface_id,
98 int32_t input_buffer_id,
99 const scoped_refptr<media::VideoFrame>& video_frame) {
100 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
101
102 TRACE_EVENT1("jpeg", "VaapiJpegDecodeAccelerator::OutputPicture",
103 "input_buffer_id", input_buffer_id);
104
105 DVLOG(3) << "Outputting VASurface " << va_surface_id
106 << " into video_frame associated with input buffer id "
107 << input_buffer_id;
108
109 VAImage image;
110 VAImageFormat format;
111 const uint32_t kI420Fourcc = VA_FOURCC('I', '4', '2', '0');
112 memset(&image, 0, sizeof(image));
113 memset(&format, 0, sizeof(format));
114 format.fourcc = kI420Fourcc;
115 format.byte_order = VA_LSB_FIRST;
116 format.bits_per_pixel = 12; // 12 for I420
117
118 void* mem = nullptr;
119 gfx::Size coded_size = video_frame->coded_size();
120 if (!vaapi_wrapper_->GetVaImage(va_surface_id, &format, coded_size, &image,
121 &mem)) {
122 DLOG(ERROR) << "Cannot get VAImage";
123 return false;
124 }
125
126 uint8* frame_mem = video_frame->data(media::VideoFrame::kYPlane);
127 size_t frame_buffer_size =
128 media::VideoFrame::AllocationSize(media::VideoFrame::I420, coded_size);
129 memcpy(frame_mem, mem, frame_buffer_size);
130
131 vaapi_wrapper_->ReturnVaImage(&image);
132
133 task_runner_->PostTask(
134 FROM_HERE, base::Bind(&VaapiJpegDecodeAccelerator::VideoFrameReady,
135 weak_this_, input_buffer_id));
136
137 return true;
138 }
139
140 void VaapiJpegDecodeAccelerator::DecodeTask(
141 const scoped_ptr<DecodeRequest>& request) {
142 DVLOG(3) << __func__;
143 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
144 TRACE_EVENT0("jpeg", "DecodeTask");
145
146 DVLOG(4) << "Mapping new input buffer id: " << request->bitstream_buffer.id()
147 << " size: " << request->bitstream_buffer.size();
148
149 scoped_ptr<base::SharedMemory> shm(
150 new base::SharedMemory(request->bitstream_buffer.handle(), true));
151 if (!shm->Map(request->bitstream_buffer.size())) {
152 LOG(ERROR) << "Failed to map input buffer";
153 NotifyErrorFromDecoderThread(request->bitstream_buffer.id(),
154 UNREADABLE_INPUT);
155 return;
156 }
157
158 media::JpegParseResult parse_result;
159
160 if (!media::ParseJpegPicture(reinterpret_cast<const uint8_t*>(shm->memory()),
161 request->bitstream_buffer.size(),
162 &parse_result)) {
163 DLOG(ERROR) << "ParseJpegPicture failed";
164 NotifyErrorFromDecoderThread(
165 request->bitstream_buffer.id(),
166 media::JpegDecodeAccelerator::PARSE_JPEG_FAILED);
167 return;
168 }
169
170 // Reuse VASurface if size doesn't change.
171 gfx::Size coded_size(parse_result.frame_header.coded_width,
172 parse_result.frame_header.coded_height);
173 if (coded_size != coded_size_ || va_surface_id_ == VA_INVALID_SURFACE) {
174 vaapi_wrapper_->DestroySurfaces();
175 va_surface_id_ = VA_INVALID_SURFACE;
176
177 std::vector<VASurfaceID> va_surfaces;
178 if (!vaapi_wrapper_->CreateSurfaces(coded_size, 1, &va_surfaces)) {
179 LOG(ERROR) << "Create VA surface failed";
180 NotifyErrorFromDecoderThread(
181 request->bitstream_buffer.id(),
182 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
183 return;
184 }
185 va_surface_id_ = va_surfaces[0];
186 coded_size_ = coded_size;
187 }
188
189 if (!VaapiJpegDecoder::Decode(vaapi_wrapper_.get(), parse_result,
190 va_surface_id_)) {
191 LOG(ERROR) << "Decode JPEG failed";
192 NotifyErrorFromDecoderThread(
193 request->bitstream_buffer.id(),
194 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
195 return;
196 }
197
198 if (!OutputPicture(va_surface_id_, request->bitstream_buffer.id(),
199 request->video_frame)) {
200 LOG(ERROR) << "Output picture failed";
201 NotifyErrorFromDecoderThread(
202 request->bitstream_buffer.id(),
203 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
204 return;
205 }
206 }
207
208 void VaapiJpegDecodeAccelerator::Decode(
209 const media::BitstreamBuffer& bitstream_buffer,
210 const scoped_refptr<media::VideoFrame>& video_frame) {
211 DVLOG(3) << __func__;
212 DCHECK(io_task_runner_->BelongsToCurrentThread());
213 TRACE_EVENT1("jpeg", "Decode", "input_id", bitstream_buffer.id());
214
215 scoped_ptr<DecodeRequest> request(
216 new DecodeRequest(bitstream_buffer, video_frame));
217
218 decoder_task_runner_->PostTask(
219 FROM_HERE, base::Bind(&VaapiJpegDecodeAccelerator::DecodeTask,
220 base::Unretained(this),
221 base::Passed(&request)));
222 }
223
224 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698