mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 13:50:40 +01:00

To avoid name collision with Timestamp type, To avoid confusion with capture time represented as Timestamp Bug: webrtc:9378 Change-Id: I8438a9cf4316e5f81d98c2af9dc9454c21c78e70 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/320601 Reviewed-by: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Rasmus Brandt <brandtr@webrtc.org> Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/main@{#40796}
277 lines
9.9 KiB
C++
277 lines
9.9 KiB
C++
/*
|
|
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "modules/video_coding/codecs/multiplex/multiplex_encoded_image_packer.h"
|
|
|
|
#include <cstring>
|
|
#include <utility>
|
|
|
|
#include "modules/rtp_rtcp/source/byte_io.h"
|
|
#include "rtc_base/checks.h"
|
|
|
|
namespace webrtc {
|
|
int PackHeader(uint8_t* buffer, MultiplexImageHeader header) {
|
|
int offset = 0;
|
|
ByteWriter<uint8_t>::WriteBigEndian(buffer + offset, header.component_count);
|
|
offset += sizeof(uint8_t);
|
|
|
|
ByteWriter<uint16_t>::WriteBigEndian(buffer + offset, header.image_index);
|
|
offset += sizeof(uint16_t);
|
|
|
|
ByteWriter<uint16_t>::WriteBigEndian(buffer + offset,
|
|
header.augmenting_data_size);
|
|
offset += sizeof(uint16_t);
|
|
|
|
ByteWriter<uint32_t>::WriteBigEndian(buffer + offset,
|
|
header.augmenting_data_offset);
|
|
offset += sizeof(uint32_t);
|
|
|
|
ByteWriter<uint32_t>::WriteBigEndian(buffer + offset,
|
|
header.first_component_header_offset);
|
|
offset += sizeof(uint32_t);
|
|
|
|
RTC_DCHECK_EQ(offset, kMultiplexImageHeaderSize);
|
|
return offset;
|
|
}
|
|
|
|
MultiplexImageHeader UnpackHeader(const uint8_t* buffer) {
|
|
MultiplexImageHeader header;
|
|
int offset = 0;
|
|
header.component_count = ByteReader<uint8_t>::ReadBigEndian(buffer + offset);
|
|
offset += sizeof(uint8_t);
|
|
|
|
header.image_index = ByteReader<uint16_t>::ReadBigEndian(buffer + offset);
|
|
offset += sizeof(uint16_t);
|
|
|
|
header.augmenting_data_size =
|
|
ByteReader<uint16_t>::ReadBigEndian(buffer + offset);
|
|
offset += sizeof(uint16_t);
|
|
|
|
header.augmenting_data_offset =
|
|
ByteReader<uint32_t>::ReadBigEndian(buffer + offset);
|
|
offset += sizeof(uint32_t);
|
|
|
|
header.first_component_header_offset =
|
|
ByteReader<uint32_t>::ReadBigEndian(buffer + offset);
|
|
offset += sizeof(uint32_t);
|
|
|
|
RTC_DCHECK_EQ(offset, kMultiplexImageHeaderSize);
|
|
return header;
|
|
}
|
|
|
|
int PackFrameHeader(uint8_t* buffer,
|
|
MultiplexImageComponentHeader frame_header) {
|
|
int offset = 0;
|
|
ByteWriter<uint32_t>::WriteBigEndian(
|
|
buffer + offset, frame_header.next_component_header_offset);
|
|
offset += sizeof(uint32_t);
|
|
|
|
ByteWriter<uint8_t>::WriteBigEndian(buffer + offset,
|
|
frame_header.component_index);
|
|
offset += sizeof(uint8_t);
|
|
|
|
ByteWriter<uint32_t>::WriteBigEndian(buffer + offset,
|
|
frame_header.bitstream_offset);
|
|
offset += sizeof(uint32_t);
|
|
|
|
ByteWriter<uint32_t>::WriteBigEndian(buffer + offset,
|
|
frame_header.bitstream_length);
|
|
offset += sizeof(uint32_t);
|
|
|
|
ByteWriter<uint8_t>::WriteBigEndian(buffer + offset, frame_header.codec_type);
|
|
offset += sizeof(uint8_t);
|
|
|
|
ByteWriter<uint8_t>::WriteBigEndian(
|
|
buffer + offset, static_cast<uint8_t>(frame_header.frame_type));
|
|
offset += sizeof(uint8_t);
|
|
|
|
RTC_DCHECK_EQ(offset, kMultiplexImageComponentHeaderSize);
|
|
return offset;
|
|
}
|
|
|
|
MultiplexImageComponentHeader UnpackFrameHeader(const uint8_t* buffer) {
|
|
MultiplexImageComponentHeader frame_header;
|
|
int offset = 0;
|
|
|
|
frame_header.next_component_header_offset =
|
|
ByteReader<uint32_t>::ReadBigEndian(buffer + offset);
|
|
offset += sizeof(uint32_t);
|
|
|
|
frame_header.component_index =
|
|
ByteReader<uint8_t>::ReadBigEndian(buffer + offset);
|
|
offset += sizeof(uint8_t);
|
|
|
|
frame_header.bitstream_offset =
|
|
ByteReader<uint32_t>::ReadBigEndian(buffer + offset);
|
|
offset += sizeof(uint32_t);
|
|
|
|
frame_header.bitstream_length =
|
|
ByteReader<uint32_t>::ReadBigEndian(buffer + offset);
|
|
offset += sizeof(uint32_t);
|
|
|
|
// This makes the wire format depend on the numeric values of the
|
|
// VideoCodecType and VideoFrameType enum constants.
|
|
frame_header.codec_type = static_cast<VideoCodecType>(
|
|
ByteReader<uint8_t>::ReadBigEndian(buffer + offset));
|
|
offset += sizeof(uint8_t);
|
|
|
|
frame_header.frame_type = static_cast<VideoFrameType>(
|
|
ByteReader<uint8_t>::ReadBigEndian(buffer + offset));
|
|
offset += sizeof(uint8_t);
|
|
|
|
RTC_DCHECK_EQ(offset, kMultiplexImageComponentHeaderSize);
|
|
return frame_header;
|
|
}
|
|
|
|
void PackBitstream(uint8_t* buffer, MultiplexImageComponent image) {
|
|
memcpy(buffer, image.encoded_image.data(), image.encoded_image.size());
|
|
}
|
|
|
|
MultiplexImage::MultiplexImage(uint16_t picture_index,
|
|
uint8_t frame_count,
|
|
std::unique_ptr<uint8_t[]> augmenting_data,
|
|
uint16_t augmenting_data_size)
|
|
: image_index(picture_index),
|
|
component_count(frame_count),
|
|
augmenting_data_size(augmenting_data_size),
|
|
augmenting_data(std::move(augmenting_data)) {}
|
|
|
|
EncodedImage MultiplexEncodedImagePacker::PackAndRelease(
|
|
const MultiplexImage& multiplex_image) {
|
|
MultiplexImageHeader header;
|
|
std::vector<MultiplexImageComponentHeader> frame_headers;
|
|
|
|
header.component_count = multiplex_image.component_count;
|
|
header.image_index = multiplex_image.image_index;
|
|
int header_offset = kMultiplexImageHeaderSize;
|
|
header.first_component_header_offset = header_offset;
|
|
header.augmenting_data_offset =
|
|
header_offset +
|
|
kMultiplexImageComponentHeaderSize * header.component_count;
|
|
header.augmenting_data_size = multiplex_image.augmenting_data_size;
|
|
int bitstream_offset =
|
|
header.augmenting_data_offset + header.augmenting_data_size;
|
|
|
|
const std::vector<MultiplexImageComponent>& images =
|
|
multiplex_image.image_components;
|
|
EncodedImage combined_image = images[0].encoded_image;
|
|
for (size_t i = 0; i < images.size(); i++) {
|
|
MultiplexImageComponentHeader frame_header;
|
|
header_offset += kMultiplexImageComponentHeaderSize;
|
|
frame_header.next_component_header_offset =
|
|
(i == images.size() - 1) ? 0 : header_offset;
|
|
frame_header.component_index = images[i].component_index;
|
|
|
|
frame_header.bitstream_offset = bitstream_offset;
|
|
frame_header.bitstream_length =
|
|
static_cast<uint32_t>(images[i].encoded_image.size());
|
|
bitstream_offset += frame_header.bitstream_length;
|
|
|
|
frame_header.codec_type = images[i].codec_type;
|
|
frame_header.frame_type = images[i].encoded_image._frameType;
|
|
|
|
// As long as one component is delta frame, we have to mark the combined
|
|
// frame as delta frame, because it is necessary for all components to be
|
|
// key frame so as to decode the whole image without previous frame data.
|
|
// Thus only when all components are key frames, we can mark the combined
|
|
// frame as key frame.
|
|
if (frame_header.frame_type == VideoFrameType::kVideoFrameDelta) {
|
|
combined_image._frameType = VideoFrameType::kVideoFrameDelta;
|
|
}
|
|
|
|
frame_headers.push_back(frame_header);
|
|
}
|
|
|
|
auto buffer = EncodedImageBuffer::Create(bitstream_offset);
|
|
combined_image.SetEncodedData(buffer);
|
|
|
|
// header
|
|
header_offset = PackHeader(buffer->data(), header);
|
|
RTC_DCHECK_EQ(header.first_component_header_offset,
|
|
kMultiplexImageHeaderSize);
|
|
|
|
// Frame Header
|
|
for (size_t i = 0; i < images.size(); i++) {
|
|
int relative_offset =
|
|
PackFrameHeader(buffer->data() + header_offset, frame_headers[i]);
|
|
RTC_DCHECK_EQ(relative_offset, kMultiplexImageComponentHeaderSize);
|
|
|
|
header_offset = frame_headers[i].next_component_header_offset;
|
|
RTC_DCHECK_EQ(header_offset,
|
|
(i == images.size() - 1)
|
|
? 0
|
|
: (kMultiplexImageHeaderSize +
|
|
kMultiplexImageComponentHeaderSize * (i + 1)));
|
|
}
|
|
|
|
// Augmenting Data
|
|
if (multiplex_image.augmenting_data_size != 0) {
|
|
memcpy(buffer->data() + header.augmenting_data_offset,
|
|
multiplex_image.augmenting_data.get(),
|
|
multiplex_image.augmenting_data_size);
|
|
}
|
|
|
|
// Bitstreams
|
|
for (size_t i = 0; i < images.size(); i++) {
|
|
PackBitstream(buffer->data() + frame_headers[i].bitstream_offset,
|
|
images[i]);
|
|
}
|
|
|
|
return combined_image;
|
|
}
|
|
|
|
MultiplexImage MultiplexEncodedImagePacker::Unpack(
|
|
const EncodedImage& combined_image) {
|
|
const MultiplexImageHeader& header = UnpackHeader(combined_image.data());
|
|
|
|
std::vector<MultiplexImageComponentHeader> frame_headers;
|
|
int header_offset = header.first_component_header_offset;
|
|
|
|
while (header_offset > 0) {
|
|
frame_headers.push_back(
|
|
UnpackFrameHeader(combined_image.data() + header_offset));
|
|
header_offset = frame_headers.back().next_component_header_offset;
|
|
}
|
|
|
|
RTC_DCHECK_LE(frame_headers.size(), header.component_count);
|
|
std::unique_ptr<uint8_t[]> augmenting_data = nullptr;
|
|
if (header.augmenting_data_size != 0) {
|
|
augmenting_data =
|
|
std::unique_ptr<uint8_t[]>(new uint8_t[header.augmenting_data_size]);
|
|
memcpy(augmenting_data.get(),
|
|
combined_image.data() + header.augmenting_data_offset,
|
|
header.augmenting_data_size);
|
|
}
|
|
|
|
MultiplexImage multiplex_image(header.image_index, header.component_count,
|
|
std::move(augmenting_data),
|
|
header.augmenting_data_size);
|
|
|
|
for (size_t i = 0; i < frame_headers.size(); i++) {
|
|
MultiplexImageComponent image_component;
|
|
image_component.component_index = frame_headers[i].component_index;
|
|
image_component.codec_type = frame_headers[i].codec_type;
|
|
|
|
EncodedImage encoded_image = combined_image;
|
|
encoded_image.SetRtpTimestamp(combined_image.RtpTimestamp());
|
|
encoded_image._frameType = frame_headers[i].frame_type;
|
|
encoded_image.SetEncodedData(EncodedImageBuffer::Create(
|
|
combined_image.data() + frame_headers[i].bitstream_offset,
|
|
frame_headers[i].bitstream_length));
|
|
|
|
image_component.encoded_image = encoded_image;
|
|
|
|
multiplex_image.image_components.push_back(image_component);
|
|
}
|
|
|
|
return multiplex_image;
|
|
}
|
|
|
|
} // namespace webrtc
|