1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and spanify to fix the errors.
#pragma allow_unsafe_buffers
#endif
#include "media/gpu/v4l2/v4l2_vp9_helpers.h"
#include "base/containers/heap_array.h"
#include "base/logging.h"
namespace media {
namespace {
// Creates superframe index from |frame_sizes|. The frame sizes is stored in the
// same bytes. For example, if the max frame size is two bytes, even if the
// smaller frame sizes are 1 byte, they are stored as two bytes. See the detail
// for VP9 Spec Annex B.
std::vector<uint8_t> CreateSuperFrameIndex(
const std::vector<uint32_t>& frame_sizes) {
if (frame_sizes.size() < 2) {
return {};
}
// Computes the bytes of the maximum frame size.
const uint32_t max_frame_size =
*std::max_element(frame_sizes.begin(), frame_sizes.end());
uint8_t bytes_per_framesize = 1;
for (uint32_t mask = 0xff; bytes_per_framesize <= 4; bytes_per_framesize++) {
if (max_frame_size < mask) {
break;
}
mask <<= 8;
mask |= 0xff;
}
uint8_t superframe_header = 0xc0;
superframe_header |= static_cast<uint8_t>(frame_sizes.size() - 1);
superframe_header |= (bytes_per_framesize - 1) << 3;
const size_t index_sz = 2 + bytes_per_framesize * frame_sizes.size();
std::vector<uint8_t> superframe_index(index_sz);
size_t pos = 0;
superframe_index[pos++] = superframe_header;
for (uint32_t size : frame_sizes) {
for (int i = 0; i < bytes_per_framesize; i++) {
superframe_index[pos++] = size & 0xff;
size >>= 8;
}
}
superframe_index[pos++] = superframe_header;
return superframe_index;
}
// Overwrites show_frame of each frame. It is set to 1 for the top spatial layer
// or otherwise 0.
bool OverwriteShowFrame(base::span<uint8_t> frame_data,
const std::vector<uint32_t>& frame_sizes) {
size_t sum_frame_size = 0;
for (uint32_t frame_size : frame_sizes) {
sum_frame_size += frame_size;
}
if (frame_data.size() != sum_frame_size) {
LOG(ERROR) << "frame data size=" << frame_data.size()
<< " is different from the sum of frame sizes"
<< " index size=" << sum_frame_size;
return false;
}
size_t offset = 0;
for (size_t i = 0; i < frame_sizes.size(); ++i) {
uint8_t* header = frame_data.data() + offset;
// See VP9 Spec Annex B.
const uint8_t frame_marker = (*header >> 6);
if (frame_marker != 0b10) {
LOG(ERROR) << "Invalid frame marker: " << static_cast<int>(frame_marker);
return false;
}
const uint8_t profile = (*header >> 4) & 0b11;
if (profile == 3) {
LOG(ERROR) << "Unsupported profile";
return false;
}
const bool show_existing_frame = (*header >> 3) & 1;
const bool show_frame = i == frame_sizes.size() - 1;
int bit = 0;
if (show_existing_frame) {
header++;
bit = 6;
} else {
bit = 1;
}
if (show_frame) {
*header |= (1u << bit);
} else {
*header &= ~(1u << bit);
}
offset += frame_sizes[i];
}
return true;
}
} // namespace
bool AppendVP9SuperFrameIndex(scoped_refptr<DecoderBuffer>& buffer) {
DCHECK(buffer->side_data());
std::vector<uint32_t> frame_sizes = buffer->side_data()->spatial_layers;
DCHECK(!frame_sizes.empty());
if (frame_sizes.size() > 3u) {
LOG(ERROR) << "The maximum number of spatial layers in VP9 is three";
return false;
}
std::vector<uint8_t> superframe_index = CreateSuperFrameIndex(frame_sizes);
const size_t vp9_superframe_size = buffer->size() + superframe_index.size();
auto vp9_superframe = base::HeapArray<uint8_t>::Uninit(vp9_superframe_size);
memcpy(vp9_superframe.data(), base::span(*buffer).data(), buffer->size());
memcpy(vp9_superframe.data() + buffer->size(), superframe_index.data(),
superframe_index.size());
if (!OverwriteShowFrame(vp9_superframe, frame_sizes)) {
return false;
}
DVLOG(3) << "DecoderBuffer is overwritten";
buffer = DecoderBuffer::FromArray(std::move(vp9_superframe));
return true;
}
} // namespace media
|