• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
17import {ArrayUtils} from 'common/array_utils';
18import {Timestamp} from 'common/time/time';
19import {AbstractParser} from 'parsers/legacy/abstract_parser';
20import {MediaBasedTraceEntry} from 'trace/media_based_trace_entry';
21import {ScreenRecordingUtils} from 'trace/screen_recording_utils';
22import {TraceType} from 'trace/trace_type';
23
24class ParserScreenRecordingLegacy extends AbstractParser<
25  MediaBasedTraceEntry,
26  bigint
27> {
28  override getTraceType(): TraceType {
29    return TraceType.SCREEN_RECORDING;
30  }
31
32  override getMagicNumber(): number[] {
33    return ParserScreenRecordingLegacy.MPEG4_MAGIC_NUMBER;
34  }
35
36  override getRealToMonotonicTimeOffsetNs(): bigint | undefined {
37    return undefined;
38  }
39
40  override getRealToBootTimeOffsetNs(): bigint | undefined {
41    return undefined;
42  }
43
44  override decodeTrace(videoData: Uint8Array): Array<bigint> {
45    const posCount = this.searchMagicString(videoData);
46    const [posTimestamps, count] = this.parseFramesCount(videoData, posCount);
47    return this.parseVideoData(videoData, posTimestamps, count);
48  }
49
50  protected override getTimestamp(decodedEntry: bigint): Timestamp {
51    return this.timestampConverter.makeTimestampFromMonotonicNs(decodedEntry);
52  }
53
54  override processDecodedEntry(
55    index: number,
56    entry: bigint,
57  ): MediaBasedTraceEntry {
58    const videoTimeSeconds = ScreenRecordingUtils.timestampToVideoTimeSeconds(
59      this.decodedEntries[0],
60      entry,
61    );
62    const videoData = this.traceFile.file;
63    return new MediaBasedTraceEntry(videoTimeSeconds, videoData);
64  }
65
66  private searchMagicString(videoData: Uint8Array): number {
67    let pos = ArrayUtils.searchSubarray(
68      videoData,
69      ParserScreenRecordingLegacy.WINSCOPE_META_MAGIC_STRING,
70    );
71    if (pos === undefined) {
72      throw new TypeError("video data doesn't contain winscope magic string");
73    }
74    pos += ParserScreenRecordingLegacy.WINSCOPE_META_MAGIC_STRING.length;
75    return pos;
76  }
77
78  private parseFramesCount(
79    videoData: Uint8Array,
80    pos: number,
81  ): [number, number] {
82    if (pos + 4 > videoData.length) {
83      throw new TypeError(
84        'Failed to parse frames count. Video data is too short.',
85      );
86    }
87    const framesCount = Number(
88      ArrayUtils.toUintLittleEndian(videoData, pos, pos + 4),
89    );
90    pos += 4;
91    return [pos, framesCount];
92  }
93
94  private parseVideoData(
95    videoData: Uint8Array,
96    pos: number,
97    count: number,
98  ): Array<bigint> {
99    if (pos + count * 8 > videoData.length) {
100      throw new TypeError(
101        'Failed to parse timestamps. Video data is too short.',
102      );
103    }
104    const timestamps: Array<bigint> = [];
105    for (let i = 0; i < count; ++i) {
106      const value =
107        ArrayUtils.toUintLittleEndian(videoData, pos, pos + 8) * 1000n;
108      pos += 8;
109      timestamps.push(value);
110    }
111    return timestamps;
112  }
113
114  private static readonly MPEG4_MAGIC_NUMBER = [
115    0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70, 0x6d, 0x70, 0x34, 0x32,
116  ]; // ....ftypmp42
117  private static readonly WINSCOPE_META_MAGIC_STRING = [
118    0x23, 0x56, 0x56, 0x31, 0x4e, 0x53, 0x43, 0x30, 0x50, 0x45, 0x54, 0x31,
119    0x4d, 0x45, 0x21, 0x23,
120  ]; // #VV1NSC0PET1ME!#
121  private static readonly EPSILON = 0.00001;
122}
123
124export {ParserScreenRecordingLegacy};
125