1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <memory>
18
19 #include "perfetto/ext/base/hash.h"
20 #include "perfetto/ext/base/string_utils.h"
21
22 #include "src/trace_processor/importers/common/args_tracker.h"
23 #include "src/trace_processor/importers/common/flow_tracker.h"
24 #include "src/trace_processor/importers/common/process_tracker.h"
25 #include "src/trace_processor/importers/common/slice_tracker.h"
26 #include "src/trace_processor/importers/common/track_tracker.h"
27 #include "src/trace_processor/importers/ftrace/v4l2_tracker.h"
28
29 #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
30 #include "protos/perfetto/trace/ftrace/v4l2.pbzero.h"
31
32 #include "v4l2_tracker.h"
33
34 namespace perfetto {
35 namespace trace_processor {
36
37 namespace {
38 using protos::pbzero::FtraceEvent;
39 using protos::pbzero::V4l2DqbufFtraceEvent;
40 using protos::pbzero::V4l2QbufFtraceEvent;
41 using protos::pbzero::Vb2V4l2BufDoneFtraceEvent;
42 using protos::pbzero::Vb2V4l2BufQueueFtraceEvent;
43 using protos::pbzero::Vb2V4l2DqbufFtraceEvent;
44 using protos::pbzero::Vb2V4l2QbufFtraceEvent;
45 using protozero::ConstBytes;
46 } // namespace
47
V4l2Tracker(TraceProcessorContext * context)48 V4l2Tracker::V4l2Tracker(TraceProcessorContext* context)
49 : context_(context),
50 buf_event_ids_(*context->storage),
51 buf_type_ids_(*context_->storage),
52 buf_field_ids_(*context->storage),
53 tc_type_ids_(*context->storage) {}
54
55 V4l2Tracker::~V4l2Tracker() = default;
56
ParseV4l2Event(uint64_t fld_id,int64_t timestamp,uint32_t pid,const ConstBytes & bytes)57 void V4l2Tracker::ParseV4l2Event(uint64_t fld_id,
58 int64_t timestamp,
59 uint32_t pid,
60 const ConstBytes& bytes) {
61 switch (fld_id) {
62 case FtraceEvent::kV4l2QbufFieldNumber: {
63 V4l2QbufFtraceEvent::Decoder pb_evt(bytes.data, bytes.size);
64 BufferEvent evt;
65 evt.device_minor = pb_evt.minor();
66 evt.index = pb_evt.index();
67 evt.type = pb_evt.type();
68 evt.bytesused = pb_evt.bytesused();
69 evt.flags = pb_evt.flags();
70 evt.field = pb_evt.field();
71 evt.timestamp = pb_evt.timestamp();
72 evt.sequence = pb_evt.sequence();
73 evt.timecode_flags = pb_evt.timecode_flags();
74 evt.timecode_frames = pb_evt.timecode_frames();
75 evt.timecode_hours = pb_evt.timecode_hours();
76 evt.timecode_minutes = pb_evt.timecode_minutes();
77 evt.timecode_seconds = pb_evt.timecode_seconds();
78 evt.timecode_type = pb_evt.timecode_type();
79 evt.timecode_userbits0 = pb_evt.timecode_userbits0();
80 evt.timecode_userbits1 = pb_evt.timecode_userbits1();
81 evt.timecode_userbits2 = pb_evt.timecode_userbits2();
82 evt.timecode_userbits3 = pb_evt.timecode_userbits3();
83
84 base::StackString<64> buf_name(
85 "VIDIOC_QBUF minor=%" PRIu32 " seq=%" PRIu32 " type=%" PRIu32
86 " index=%" PRIu32,
87 evt.device_minor, evt.sequence, *evt.type, *evt.index);
88
89 StringId buf_name_id =
90 context_->storage->InternString(buf_name.string_view());
91 std::optional<SliceId> slice_id =
92 AddSlice(buf_name_id, timestamp, pid, evt);
93
94 uint64_t hash = base::Hasher::Combine(evt.device_minor, evt.sequence,
95 *evt.type, *evt.index);
96
97 QueuedBuffer queued_buffer;
98 queued_buffer.queue_slice_id = slice_id;
99
100 queued_buffers_.Insert(hash, std::move(queued_buffer));
101 break;
102 }
103 case FtraceEvent::kV4l2DqbufFieldNumber: {
104 V4l2DqbufFtraceEvent::Decoder pb_evt(bytes.data, bytes.size);
105 BufferEvent evt;
106 evt.device_minor = pb_evt.minor();
107 evt.index = pb_evt.index();
108 evt.type = pb_evt.type();
109 evt.bytesused = pb_evt.bytesused();
110 evt.flags = pb_evt.flags();
111 evt.field = pb_evt.field();
112 evt.timestamp = pb_evt.timestamp();
113 evt.sequence = pb_evt.sequence();
114 evt.timecode_flags = pb_evt.timecode_flags();
115 evt.timecode_frames = pb_evt.timecode_frames();
116 evt.timecode_hours = pb_evt.timecode_hours();
117 evt.timecode_minutes = pb_evt.timecode_minutes();
118 evt.timecode_seconds = pb_evt.timecode_seconds();
119 evt.timecode_type = pb_evt.timecode_type();
120 evt.timecode_userbits0 = pb_evt.timecode_userbits0();
121 evt.timecode_userbits1 = pb_evt.timecode_userbits1();
122 evt.timecode_userbits2 = pb_evt.timecode_userbits2();
123 evt.timecode_userbits3 = pb_evt.timecode_userbits3();
124
125 base::StackString<64> buf_name(
126 "VIDIOC_DQBUF minor=%" PRIu32 " seq=%" PRIu32 " type=%" PRIu32
127 " index=%" PRIu32,
128 evt.device_minor, evt.sequence, *evt.type, *evt.index);
129
130 StringId buf_name_id =
131 context_->storage->InternString(buf_name.string_view());
132 std::optional<SliceId> slice_id =
133 AddSlice(buf_name_id, timestamp, pid, evt);
134
135 uint64_t hash = base::Hasher::Combine(evt.device_minor, evt.sequence,
136 *evt.type, *evt.index);
137
138 const QueuedBuffer* queued_buffer = queued_buffers_.Find(hash);
139 if (queued_buffer) {
140 if (queued_buffer->queue_slice_id && slice_id) {
141 context_->flow_tracker->InsertFlow(*queued_buffer->queue_slice_id,
142 *slice_id);
143 }
144
145 queued_buffers_.Erase(hash);
146 }
147 break;
148 }
149 case FtraceEvent::kVb2V4l2BufQueueFieldNumber: {
150 Vb2V4l2BufQueueFtraceEvent::Decoder pb_evt(bytes.data, bytes.size);
151 BufferEvent evt;
152 evt.device_minor = pb_evt.minor();
153 evt.index = std::nullopt;
154 evt.type = std::nullopt;
155 evt.bytesused = std::nullopt;
156 evt.flags = pb_evt.flags();
157 evt.field = pb_evt.field();
158 evt.timestamp = pb_evt.timestamp();
159 evt.sequence = pb_evt.sequence();
160 evt.timecode_flags = pb_evt.timecode_flags();
161 evt.timecode_frames = pb_evt.timecode_frames();
162 evt.timecode_hours = pb_evt.timecode_hours();
163 evt.timecode_minutes = pb_evt.timecode_minutes();
164 evt.timecode_seconds = pb_evt.timecode_seconds();
165 evt.timecode_type = pb_evt.timecode_type();
166 evt.timecode_userbits0 = pb_evt.timecode_userbits0();
167 evt.timecode_userbits1 = pb_evt.timecode_userbits1();
168 evt.timecode_userbits2 = pb_evt.timecode_userbits2();
169 evt.timecode_userbits3 = pb_evt.timecode_userbits3();
170
171 base::StackString<64> buf_name("vb2_v4l2_buf_queue minor=%" PRIu32
172 " seq=%" PRIu32 " type=0 index=0",
173 evt.device_minor, evt.sequence);
174
175 StringId buf_name_id =
176 context_->storage->InternString(buf_name.string_view());
177 AddSlice(buf_name_id, timestamp, pid, evt);
178 break;
179 }
180 case FtraceEvent::kVb2V4l2BufDoneFieldNumber: {
181 Vb2V4l2BufDoneFtraceEvent::Decoder pb_evt(bytes.data, bytes.size);
182 BufferEvent evt;
183 evt.device_minor = pb_evt.minor();
184 evt.index = std::nullopt;
185 evt.type = std::nullopt;
186 evt.bytesused = std::nullopt;
187 evt.flags = pb_evt.flags();
188 evt.field = pb_evt.field();
189 evt.timestamp = pb_evt.timestamp();
190 evt.sequence = pb_evt.sequence();
191 evt.timecode_flags = pb_evt.timecode_flags();
192 evt.timecode_frames = pb_evt.timecode_frames();
193 evt.timecode_hours = pb_evt.timecode_hours();
194 evt.timecode_minutes = pb_evt.timecode_minutes();
195 evt.timecode_seconds = pb_evt.timecode_seconds();
196 evt.timecode_type = pb_evt.timecode_type();
197 evt.timecode_userbits0 = pb_evt.timecode_userbits0();
198 evt.timecode_userbits1 = pb_evt.timecode_userbits1();
199 evt.timecode_userbits2 = pb_evt.timecode_userbits2();
200 evt.timecode_userbits3 = pb_evt.timecode_userbits3();
201
202 base::StackString<64> buf_name("vb2_v4l2_buf_done minor=%" PRIu32
203 " seq=%" PRIu32 " type=0 index=0",
204 evt.device_minor, evt.sequence);
205
206 StringId buf_name_id =
207 context_->storage->InternString(buf_name.string_view());
208 AddSlice(buf_name_id, timestamp, pid, evt);
209 break;
210 }
211 case FtraceEvent::kVb2V4l2QbufFieldNumber: {
212 Vb2V4l2QbufFtraceEvent::Decoder pb_evt(bytes.data, bytes.size);
213 BufferEvent evt;
214 evt.device_minor = pb_evt.minor();
215 evt.index = std::nullopt;
216 evt.type = std::nullopt;
217 evt.bytesused = std::nullopt;
218 evt.flags = pb_evt.flags();
219 evt.field = pb_evt.field();
220 evt.timestamp = pb_evt.timestamp();
221 evt.sequence = pb_evt.sequence();
222 evt.timecode_flags = pb_evt.timecode_flags();
223 evt.timecode_frames = pb_evt.timecode_frames();
224 evt.timecode_hours = pb_evt.timecode_hours();
225 evt.timecode_minutes = pb_evt.timecode_minutes();
226 evt.timecode_seconds = pb_evt.timecode_seconds();
227 evt.timecode_type = pb_evt.timecode_type();
228 evt.timecode_userbits0 = pb_evt.timecode_userbits0();
229 evt.timecode_userbits1 = pb_evt.timecode_userbits1();
230 evt.timecode_userbits2 = pb_evt.timecode_userbits2();
231 evt.timecode_userbits3 = pb_evt.timecode_userbits3();
232
233 base::StackString<64> buf_name("vb2_v4l2_qbuf minor=%" PRIu32
234 " seq=%" PRIu32 " type=0 index=0",
235 evt.device_minor, evt.sequence);
236
237 StringId buf_name_id =
238 context_->storage->InternString(buf_name.string_view());
239 AddSlice(buf_name_id, timestamp, pid, evt);
240 break;
241 }
242 case FtraceEvent::kVb2V4l2DqbufFieldNumber: {
243 Vb2V4l2DqbufFtraceEvent::Decoder pb_evt(bytes.data, bytes.size);
244 BufferEvent evt;
245 evt.device_minor = pb_evt.minor();
246 evt.index = std::nullopt;
247 evt.type = std::nullopt;
248 evt.bytesused = std::nullopt;
249 evt.flags = pb_evt.flags();
250 evt.field = pb_evt.field();
251 evt.timestamp = pb_evt.timestamp();
252 evt.sequence = pb_evt.sequence();
253 evt.timecode_flags = pb_evt.timecode_flags();
254 evt.timecode_frames = pb_evt.timecode_frames();
255 evt.timecode_hours = pb_evt.timecode_hours();
256 evt.timecode_minutes = pb_evt.timecode_minutes();
257 evt.timecode_seconds = pb_evt.timecode_seconds();
258 evt.timecode_type = pb_evt.timecode_type();
259 evt.timecode_userbits0 = pb_evt.timecode_userbits0();
260 evt.timecode_userbits1 = pb_evt.timecode_userbits1();
261 evt.timecode_userbits2 = pb_evt.timecode_userbits2();
262 evt.timecode_userbits3 = pb_evt.timecode_userbits3();
263
264 base::StackString<64> buf_name("vb2_v4l2_qbuf minor=%" PRIu32
265 " seq=%" PRIu32 " type=0 index=0",
266 evt.device_minor, evt.sequence);
267
268 StringId buf_name_id =
269 context_->storage->InternString(buf_name.string_view());
270 AddSlice(buf_name_id, timestamp, pid, evt);
271 break;
272 }
273 default:
274 break;
275 }
276 }
277
AddSlice(StringId buf_name_id,int64_t timestamp,uint32_t pid,const BufferEvent & evt)278 std::optional<SliceId> V4l2Tracker::AddSlice(StringId buf_name_id,
279 int64_t timestamp,
280 uint32_t pid,
281 const BufferEvent& evt) {
282 UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
283 TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
284
285 std::optional<SliceId> slice_id = context_->slice_tracker->Scoped(
286 timestamp, track_id, buf_event_ids_.v4l2, buf_name_id, 0,
287 [this, &evt](ArgsTracker::BoundInserter* inserter) {
288 this->AddArgs(evt, inserter);
289 });
290
291 return slice_id;
292 }
293
AddArgs(const BufferEvent & evt,ArgsTracker::BoundInserter * inserter)294 void V4l2Tracker::AddArgs(const BufferEvent& evt,
295 ArgsTracker::BoundInserter* inserter) {
296 inserter->AddArg(buf_event_ids_.device_minor,
297 Variadic::Integer(evt.device_minor));
298
299 if (evt.index)
300 inserter->AddArg(buf_event_ids_.index, Variadic::Integer(*evt.index));
301 if (evt.type)
302 inserter->AddArg(buf_event_ids_.type,
303 Variadic::String(buf_type_ids_.Map(*evt.type)));
304 if (evt.bytesused)
305 inserter->AddArg(buf_event_ids_.bytesused,
306 Variadic::Integer(*evt.bytesused));
307
308 inserter->AddArg(buf_event_ids_.flags,
309 Variadic::String(InternBufFlags(evt.flags)));
310 inserter->AddArg(buf_event_ids_.field,
311 Variadic::String(buf_field_ids_.Map(evt.field)));
312 inserter->AddArg(buf_event_ids_.timestamp, Variadic::Integer(evt.timestamp));
313 inserter->AddArg(buf_event_ids_.timecode_type,
314 Variadic::String(tc_type_ids_.Map(evt.timecode_type)));
315 inserter->AddArg(buf_event_ids_.timecode_flags,
316 Variadic::String(InternTcFlags(evt.timecode_flags)));
317 inserter->AddArg(buf_event_ids_.timecode_frames,
318 Variadic::Integer(evt.timecode_frames));
319 inserter->AddArg(buf_event_ids_.timecode_seconds,
320 Variadic::Integer(evt.timecode_seconds));
321 inserter->AddArg(buf_event_ids_.timecode_minutes,
322 Variadic::Integer(evt.timecode_minutes));
323 inserter->AddArg(buf_event_ids_.timecode_hours,
324 Variadic::Integer(evt.timecode_hours));
325 inserter->AddArg(buf_event_ids_.timecode_userbits0,
326 Variadic::Integer(evt.timecode_userbits0));
327 inserter->AddArg(buf_event_ids_.timecode_userbits1,
328 Variadic::Integer(evt.timecode_userbits1));
329 inserter->AddArg(buf_event_ids_.timecode_userbits2,
330 Variadic::Integer(evt.timecode_userbits2));
331 inserter->AddArg(buf_event_ids_.timecode_userbits3,
332 Variadic::Integer(evt.timecode_userbits3));
333 inserter->AddArg(buf_event_ids_.sequence, Variadic::Integer(evt.sequence));
334 }
335
BufferEventStringIds(TraceStorage & storage)336 V4l2Tracker::BufferEventStringIds::BufferEventStringIds(TraceStorage& storage)
337 : v4l2(storage.InternString("Video 4 Linux 2")),
338 v4l2_qbuf(storage.InternString("v4l2_qbuf")),
339 v4l2_dqbuf(storage.InternString("v4l2_dqbuf")),
340 device_minor(storage.InternString("minor")),
341 index(storage.InternString("index")),
342 type(storage.InternString("type")),
343 bytesused(storage.InternString("bytesused")),
344 flags(storage.InternString("flags")),
345 field(storage.InternString("field")),
346 timestamp(storage.InternString("timestamp")),
347 timecode_type(storage.InternString("timecode_type")),
348 timecode_flags(storage.InternString("timecode_flags")),
349 timecode_frames(storage.InternString("timecode_frames")),
350 timecode_seconds(storage.InternString("timecode_seconds")),
351 timecode_minutes(storage.InternString("timecode_minutes")),
352 timecode_hours(storage.InternString("timecode_hours")),
353 timecode_userbits0(storage.InternString("timecode_userbits0")),
354 timecode_userbits1(storage.InternString("timecode_userbits1")),
355 timecode_userbits2(storage.InternString("timecode_userbits2")),
356 timecode_userbits3(storage.InternString("timecode_userbits3")),
357 sequence(storage.InternString("sequence")) {}
358
BufferTypeStringIds(TraceStorage & storage)359 V4l2Tracker::BufferTypeStringIds::BufferTypeStringIds(TraceStorage& storage)
360 : video_capture(storage.InternString("VIDEO_CAPTURE")),
361 video_output(storage.InternString("VIDEO_OUTPUT")),
362 video_overlay(storage.InternString("VIDEO_OVERLAY")),
363 vbi_capture(storage.InternString("VBI_CAPTURE")),
364 vbi_output(storage.InternString("VBI_OUTPUT")),
365 sliced_vbi_capture(storage.InternString("SLICED_VBI_CAPTURE")),
366 sliced_vbi_output(storage.InternString("SLICED_VBI_OUTPUT")),
367 video_output_overlay(storage.InternString("VIDEO_OUTPUT_OVERLAY")),
368 video_capture_mplane(storage.InternString("VIDEO_CAPTURE_MPLANE")),
369 video_output_mplane(storage.InternString("VIDEO_OUTPUT_MPLANE")),
370 sdr_capture(storage.InternString("SDR_CAPTURE")),
371 sdr_output(storage.InternString("SDR_OUTPUT")),
372 meta_capture(storage.InternString("META_CAPTURE")),
373 meta_output(storage.InternString("META_OUTPUT")),
374 priv(storage.InternString("PRIVATE")) {}
375
Map(uint32_t buf_type)376 StringId V4l2Tracker::BufferTypeStringIds::Map(uint32_t buf_type) {
377 // Values taken from linux/videodev2.h
378 switch (buf_type) {
379 case 1:
380 return video_capture;
381 case 2:
382 return video_output;
383 case 3:
384 return video_overlay;
385 case 4:
386 return vbi_capture;
387 case 5:
388 return vbi_output;
389 case 6:
390 return sliced_vbi_capture;
391 case 7:
392 return sliced_vbi_output;
393 case 8:
394 return video_output_overlay;
395 case 9:
396 return video_capture_mplane;
397 case 10:
398 return video_output_mplane;
399 case 11:
400 return sdr_capture;
401 case 12:
402 return sdr_output;
403 case 13:
404 return meta_capture;
405 case 14:
406 return meta_output;
407 case 0x80:
408 return priv;
409 default:
410 return kNullStringId;
411 }
412 }
413
BufferFieldStringIds(TraceStorage & storage)414 V4l2Tracker::BufferFieldStringIds::BufferFieldStringIds(TraceStorage& storage)
415 : any(storage.InternString("ANY")),
416 none(storage.InternString("NONE")),
417 top(storage.InternString("TOP")),
418 bottom(storage.InternString("BOTTOM")),
419 interlaced(storage.InternString("INTERLACED")),
420 seq_tb(storage.InternString("SEQ_TB")),
421 seq_bt(storage.InternString("SEQ_BT")),
422 alternate(storage.InternString("ALTERNATE")),
423 interlaced_tb(storage.InternString("INTERLACED_TB")),
424 interlaced_bt(storage.InternString("INTERLACED_BT")) {}
425
Map(uint32_t field)426 StringId V4l2Tracker::BufferFieldStringIds::Map(uint32_t field) {
427 // Values taken from linux/videodev2.h
428 switch (field) {
429 case 0:
430 return any;
431 case 1:
432 return none;
433 case 2:
434 return top;
435 case 3:
436 return bottom;
437 case 4:
438 return interlaced;
439 case 5:
440 return seq_tb;
441 case 6:
442 return seq_bt;
443 case 7:
444 return alternate;
445 case 8:
446 return interlaced_tb;
447 case 9:
448 return interlaced_bt;
449 default:
450 return kNullStringId;
451 }
452 }
453
TimecodeTypeStringIds(TraceStorage & storage)454 V4l2Tracker::TimecodeTypeStringIds::TimecodeTypeStringIds(TraceStorage& storage)
455 : type_24fps(storage.InternString("24FPS")),
456 type_25fps(storage.InternString("25FPS")),
457 type_30fps(storage.InternString("30FPS")),
458 type_50fps(storage.InternString("50FPS")),
459 type_60fps(storage.InternString("60FPS")) {}
460
Map(uint32_t type)461 StringId V4l2Tracker::TimecodeTypeStringIds::Map(uint32_t type) {
462 switch (type) {
463 case 1:
464 return type_24fps;
465 case 2:
466 return type_25fps;
467 case 3:
468 return type_30fps;
469 case 4:
470 return type_50fps;
471 case 5:
472 return type_60fps;
473 default:
474 return kNullStringId;
475 }
476 }
477
InternBufFlags(uint32_t flags)478 StringId V4l2Tracker::InternBufFlags(uint32_t flags) {
479 std::vector<std::string> present_flags;
480
481 if (flags & 0x00000001)
482 present_flags.push_back("MAPPED");
483 if (flags & 0x00000002)
484 present_flags.push_back("QUEUED");
485 if (flags & 0x00000004)
486 present_flags.push_back("DONE");
487 if (flags & 0x00000008)
488 present_flags.push_back("KEYFRAME");
489 if (flags & 0x00000010)
490 present_flags.push_back("PFRAME");
491 if (flags & 0x00000020)
492 present_flags.push_back("BFRAME");
493 if (flags & 0x00000040)
494 present_flags.push_back("ERROR");
495 if (flags & 0x00000080)
496 present_flags.push_back("IN_REQUEST");
497 if (flags & 0x00000100)
498 present_flags.push_back("TIMECODE");
499 if (flags & 0x00000200)
500 present_flags.push_back("M2M_HOLD_CAPTURE_BUF");
501 if (flags & 0x00000400)
502 present_flags.push_back("PREPARED");
503 if (flags & 0x00000800)
504 present_flags.push_back("NO_CACHE_INVALIDATE");
505 if (flags & 0x00001000)
506 present_flags.push_back("NO_CACHE_CLEAN");
507 if (flags & 0x0000e000)
508 present_flags.push_back("TIMESTAMP_MASK");
509 if (flags == 0x00000000)
510 present_flags.push_back("TIMESTAMP_UNKNOWN");
511 if (flags & 0x00002000)
512 present_flags.push_back("TIMESTAMP_MONOTONIC");
513 if (flags & 0x00004000)
514 present_flags.push_back("TIMESTAMP_COPY");
515 if (flags & 0x00070000)
516 present_flags.push_back("TSTAMP_SRC_MASK");
517 if (flags == 0x00000000)
518 present_flags.push_back("TSTAMP_SRC_EOF");
519 if (flags & 0x00010000)
520 present_flags.push_back("TSTAMP_SRC_SOE");
521 if (flags & 0x00100000)
522 present_flags.push_back("LAST");
523 if (flags & 0x00800000)
524 present_flags.push_back("REQUEST_FD");
525
526 return context_->storage->InternString(
527 base::Join(present_flags, "|").c_str());
528 }
529
InternTcFlags(uint32_t flags)530 StringId V4l2Tracker::InternTcFlags(uint32_t flags) {
531 std::vector<std::string> present_flags;
532
533 if (flags == 0x0000)
534 present_flags.push_back("USERBITS_USERDEFINED");
535 if (flags & 0x0001)
536 present_flags.push_back("FLAG_DROPFRAME");
537 if (flags & 0x0002)
538 present_flags.push_back("FLAG_COLORFRAME");
539 if ((flags & 0x000C) == 0x0004)
540 present_flags.push_back("USERBITS_field(01)");
541 if ((flags & 0x000C) == 0x0008)
542 present_flags.push_back("USERBITS_field(10)");
543 if ((flags & 0x000C) == 0x000C)
544 present_flags.push_back("USERBITS_field(11)");
545 if (flags & 0x0008)
546 present_flags.push_back("USERBITS_8BITCHARS");
547
548 return context_->storage->InternString(
549 base::Join(present_flags, "|").c_str());
550 }
551
552 } // namespace trace_processor
553 } // namespace perfetto
554