• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2020 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "host-common/MediaSnapshotHelper.h"
16 #include "host-common/H264NaluParser.h"
17 #include "host-common/VpxFrameParser.h"
18 
19 #define MEDIA_SNAPSHOT_DEBUG 0
20 
21 #if MEDIA_SNAPSHOT_DEBUG
22 #define SNAPSHOT_DPRINT(fmt, ...)                                       \
23     fprintf(stderr, "media-snapshot-helper: %s:%d " fmt "\n", __func__, \
24             __LINE__, ##__VA_ARGS__);
25 #else
26 #define SNAPSHOT_DPRINT(fmt, ...)
27 #endif
28 
29 namespace android {
30 namespace emulation {
31 
32 using PacketInfo = MediaSnapshotState::PacketInfo;
33 using ColorAspects = MediaSnapshotState::ColorAspects;
34 
savePacket(const uint8_t * frame,size_t szBytes,uint64_t inputPts)35 void MediaSnapshotHelper::savePacket(const uint8_t* frame,
36                                      size_t szBytes,
37                                      uint64_t inputPts) {
38     if (mType == CodecType::H264) {
39         return saveH264Packet(frame, szBytes, inputPts);
40     } else {
41         return saveVPXPacket(frame, szBytes, inputPts);
42     }
43 }
44 
saveVPXPacket(const uint8_t * data,size_t len,uint64_t user_priv)45 void MediaSnapshotHelper::saveVPXPacket(const uint8_t* data,
46                                         size_t len,
47                                         uint64_t user_priv) {
48     const bool enableSnapshot = true;
49     if (enableSnapshot) {
50         VpxFrameParser fparser(mType == CodecType::VP8 ? 8 : 9, data,
51                                (size_t)len);
52         SNAPSHOT_DPRINT("found frame type: %s frame",
53                         fparser.isKeyFrame() ? "KEY" : "NON-KEY");
54         std::vector<uint8_t> v;
55         v.assign(data, data + len);
56         bool isIFrame = fparser.isKeyFrame();
57         if (isIFrame) {
58             mSnapshotState.savedPackets.clear();
59         }
60         const bool saveOK = mSnapshotState.savePacket(v, user_priv);
61         if (saveOK) {
62             SNAPSHOT_DPRINT("saving packet of isze %d; total is %d",
63                             (int)(v.size()),
64                             (int)(mSnapshotState.savedPackets.size()));
65         } else {
66             SNAPSHOT_DPRINT("saving packet; has duplicate, skip; total is %d",
67                             (int)(mSnapshotState.savedPackets.size()));
68         }
69     }
70 }
71 
saveH264Packet(const uint8_t * frame,size_t szBytes,uint64_t inputPts)72 void MediaSnapshotHelper::saveH264Packet(const uint8_t* frame,
73                                          size_t szBytes,
74                                          uint64_t inputPts) {
75     const bool enableSnapshot = true;
76     if (enableSnapshot) {
77         std::vector<uint8_t> v;
78         v.assign(frame, frame + szBytes);
79         bool hasSps = H264NaluParser::checkSpsFrame(frame, szBytes);
80         if (hasSps) {
81             SNAPSHOT_DPRINT("create new snapshot state");
82             MediaSnapshotState newSnapshotState{};
83             // we need to keep the frames, the guest might not have retrieved
84             // them yet; otherwise, we might loose some frames
85             std::swap(newSnapshotState.savedFrames, mSnapshotState.savedFrames);
86             std::swap(newSnapshotState, mSnapshotState);
87             mSnapshotState.saveSps(v);
88         } else {
89             bool hasPps = H264NaluParser::checkPpsFrame(frame, szBytes);
90             if (hasPps) {
91                 mSnapshotState.savePps(v);
92                 mSnapshotState.savedPackets.clear();
93                 mSnapshotState.savedDecodedFrame.data.clear();
94             } else {
95                 bool isIFrame = H264NaluParser::checkIFrame(frame, szBytes);
96                 if (isIFrame) {
97                     mSnapshotState.savedPackets.clear();
98                 }
99                 mSnapshotState.savePacket(std::move(v), inputPts);
100                 SNAPSHOT_DPRINT("saving packet; total is %d",
101                                 (int)(mSnapshotState.savedPackets.size()));
102             }
103         }
104     }
105 }
save(base::Stream * stream) const106 void MediaSnapshotHelper::save(base::Stream* stream) const {
107     SNAPSHOT_DPRINT("saving packets now %d",
108                     (int)(mSnapshotState.savedPackets.size()));
109     if (mType == CodecType::H264) {
110         stream->putBe32(264);
111     } else if (mType == CodecType::VP8) {
112         stream->putBe32(8);
113     } else if (mType == CodecType::VP9) {
114         stream->putBe32(9);
115     }
116     mSnapshotState.save(stream);
117 }
118 
replay(std::function<void (uint8_t * data,size_t len,uint64_t pts)> oneShotDecode)119 void MediaSnapshotHelper::replay(
120         std::function<void(uint8_t* data, size_t len, uint64_t pts)>
121                 oneShotDecode) {
122     if (mSnapshotState.sps.size() > 0) {
123         oneShotDecode(mSnapshotState.sps.data(), mSnapshotState.sps.size(), 0);
124         if (mSnapshotState.pps.size() > 0) {
125             oneShotDecode(mSnapshotState.pps.data(), mSnapshotState.pps.size(),
126                           0);
127             for (int i = 0; i < mSnapshotState.savedPackets.size(); ++i) {
128                 MediaSnapshotState::PacketInfo& pkt =
129                         mSnapshotState.savedPackets[i];
130                 SNAPSHOT_DPRINT("reloading frame %d size %d", i,
131                                 (int)pkt.data.size());
132                 oneShotDecode(pkt.data.data(), pkt.data.size(), pkt.pts);
133             }
134         }
135     }
136 }
137 
load(base::Stream * stream,std::function<void (uint8_t * data,size_t len,uint64_t pts)> oneShotDecode)138 void MediaSnapshotHelper::load(
139         base::Stream* stream,
140         std::function<void(uint8_t* data, size_t len, uint64_t pts)>
141                 oneShotDecode) {
142     int type = stream->getBe32();
143     if (type == 264) {
144         mType = CodecType::H264;
145     } else if (type == 8) {
146         mType = CodecType::VP8;
147     } else if (type == 9) {
148         mType = CodecType::VP9;
149     }
150 
151     mSnapshotState.load(stream);
152 
153     SNAPSHOT_DPRINT("loaded packets %d, now restore decoder",
154                     (int)(mSnapshotState.savedPackets.size()));
155 
156     replay(oneShotDecode);
157 
158     SNAPSHOT_DPRINT("Done loading snapshots frames\n\n");
159 }
160 
161 }  // namespace emulation
162 }  // namespace android
163