You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
6.0 KiB
163 lines
6.0 KiB
// Copyright (C) 2020 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "host-common/MediaSnapshotHelper.h"
|
|
#include "host-common/H264NaluParser.h"
|
|
#include "host-common/VpxFrameParser.h"
|
|
|
|
#define MEDIA_SNAPSHOT_DEBUG 0
|
|
|
|
#if MEDIA_SNAPSHOT_DEBUG
|
|
#define SNAPSHOT_DPRINT(fmt, ...) \
|
|
fprintf(stderr, "media-snapshot-helper: %s:%d " fmt "\n", __func__, \
|
|
__LINE__, ##__VA_ARGS__);
|
|
#else
|
|
#define SNAPSHOT_DPRINT(fmt, ...)
|
|
#endif
|
|
|
|
namespace android {
|
|
namespace emulation {
|
|
|
|
using PacketInfo = MediaSnapshotState::PacketInfo;
|
|
using ColorAspects = MediaSnapshotState::ColorAspects;
|
|
|
|
void MediaSnapshotHelper::savePacket(const uint8_t* frame,
|
|
size_t szBytes,
|
|
uint64_t inputPts) {
|
|
if (mType == CodecType::H264) {
|
|
return saveH264Packet(frame, szBytes, inputPts);
|
|
} else {
|
|
return saveVPXPacket(frame, szBytes, inputPts);
|
|
}
|
|
}
|
|
|
|
void MediaSnapshotHelper::saveVPXPacket(const uint8_t* data,
|
|
size_t len,
|
|
uint64_t user_priv) {
|
|
const bool enableSnapshot = true;
|
|
if (enableSnapshot) {
|
|
VpxFrameParser fparser(mType == CodecType::VP8 ? 8 : 9, data,
|
|
(size_t)len);
|
|
SNAPSHOT_DPRINT("found frame type: %s frame",
|
|
fparser.isKeyFrame() ? "KEY" : "NON-KEY");
|
|
std::vector<uint8_t> v;
|
|
v.assign(data, data + len);
|
|
bool isIFrame = fparser.isKeyFrame();
|
|
if (isIFrame) {
|
|
mSnapshotState.savedPackets.clear();
|
|
}
|
|
const bool saveOK = mSnapshotState.savePacket(v, user_priv);
|
|
if (saveOK) {
|
|
SNAPSHOT_DPRINT("saving packet of isze %d; total is %d",
|
|
(int)(v.size()),
|
|
(int)(mSnapshotState.savedPackets.size()));
|
|
} else {
|
|
SNAPSHOT_DPRINT("saving packet; has duplicate, skip; total is %d",
|
|
(int)(mSnapshotState.savedPackets.size()));
|
|
}
|
|
}
|
|
}
|
|
|
|
void MediaSnapshotHelper::saveH264Packet(const uint8_t* frame,
|
|
size_t szBytes,
|
|
uint64_t inputPts) {
|
|
const bool enableSnapshot = true;
|
|
if (enableSnapshot) {
|
|
std::vector<uint8_t> v;
|
|
v.assign(frame, frame + szBytes);
|
|
bool hasSps = H264NaluParser::checkSpsFrame(frame, szBytes);
|
|
if (hasSps) {
|
|
SNAPSHOT_DPRINT("create new snapshot state");
|
|
MediaSnapshotState newSnapshotState{};
|
|
// we need to keep the frames, the guest might not have retrieved
|
|
// them yet; otherwise, we might loose some frames
|
|
std::swap(newSnapshotState.savedFrames, mSnapshotState.savedFrames);
|
|
std::swap(newSnapshotState, mSnapshotState);
|
|
mSnapshotState.saveSps(v);
|
|
} else {
|
|
bool hasPps = H264NaluParser::checkPpsFrame(frame, szBytes);
|
|
if (hasPps) {
|
|
mSnapshotState.savePps(v);
|
|
mSnapshotState.savedPackets.clear();
|
|
mSnapshotState.savedDecodedFrame.data.clear();
|
|
} else {
|
|
bool isIFrame = H264NaluParser::checkIFrame(frame, szBytes);
|
|
if (isIFrame) {
|
|
mSnapshotState.savedPackets.clear();
|
|
}
|
|
mSnapshotState.savePacket(std::move(v), inputPts);
|
|
SNAPSHOT_DPRINT("saving packet; total is %d",
|
|
(int)(mSnapshotState.savedPackets.size()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void MediaSnapshotHelper::save(base::Stream* stream) const {
|
|
SNAPSHOT_DPRINT("saving packets now %d",
|
|
(int)(mSnapshotState.savedPackets.size()));
|
|
if (mType == CodecType::H264) {
|
|
stream->putBe32(264);
|
|
} else if (mType == CodecType::VP8) {
|
|
stream->putBe32(8);
|
|
} else if (mType == CodecType::VP9) {
|
|
stream->putBe32(9);
|
|
}
|
|
mSnapshotState.save(stream);
|
|
}
|
|
|
|
void MediaSnapshotHelper::replay(
|
|
std::function<void(uint8_t* data, size_t len, uint64_t pts)>
|
|
oneShotDecode) {
|
|
if (mSnapshotState.sps.size() > 0) {
|
|
oneShotDecode(mSnapshotState.sps.data(), mSnapshotState.sps.size(), 0);
|
|
if (mSnapshotState.pps.size() > 0) {
|
|
oneShotDecode(mSnapshotState.pps.data(), mSnapshotState.pps.size(),
|
|
0);
|
|
for (int i = 0; i < mSnapshotState.savedPackets.size(); ++i) {
|
|
MediaSnapshotState::PacketInfo& pkt =
|
|
mSnapshotState.savedPackets[i];
|
|
SNAPSHOT_DPRINT("reloading frame %d size %d", i,
|
|
(int)pkt.data.size());
|
|
oneShotDecode(pkt.data.data(), pkt.data.size(), pkt.pts);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MediaSnapshotHelper::load(
|
|
base::Stream* stream,
|
|
std::function<void(uint8_t* data, size_t len, uint64_t pts)>
|
|
oneShotDecode) {
|
|
int type = stream->getBe32();
|
|
if (type == 264) {
|
|
mType = CodecType::H264;
|
|
} else if (type == 8) {
|
|
mType = CodecType::VP8;
|
|
} else if (type == 9) {
|
|
mType = CodecType::VP9;
|
|
}
|
|
|
|
mSnapshotState.load(stream);
|
|
|
|
SNAPSHOT_DPRINT("loaded packets %d, now restore decoder",
|
|
(int)(mSnapshotState.savedPackets.size()));
|
|
|
|
replay(oneShotDecode);
|
|
|
|
SNAPSHOT_DPRINT("Done loading snapshots frames\n\n");
|
|
}
|
|
|
|
} // namespace emulation
|
|
} // namespace android
|