xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/ftrace/v4l2_tracker.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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