Add H.265 byte to unit stream converter.
Also renames NaluReader::NaluType to CodecType. Issue #46 Change-Id: I37d21fcb1109659f14baf43308a94c5e2d9ac2d1
This commit is contained in:
parent
f1e4f74a14
commit
404660cbdb
|
@ -23,10 +23,14 @@
|
|||
'h264_byte_to_unit_stream_converter.h',
|
||||
'h264_parser.cc',
|
||||
'h264_parser.h',
|
||||
'h265_byte_to_unit_stream_converter.cc',
|
||||
'h265_byte_to_unit_stream_converter.h',
|
||||
'h265_parser.cc',
|
||||
'h265_parser.h',
|
||||
'h26x_bit_reader.cc',
|
||||
'h26x_bit_reader.h',
|
||||
'h26x_byte_to_unit_stream_converter.cc',
|
||||
'h26x_byte_to_unit_stream_converter.h',
|
||||
'hevc_decoder_configuration.cc',
|
||||
'hevc_decoder_configuration.h',
|
||||
'nal_unit_to_byte_stream_converter.cc',
|
||||
|
@ -53,6 +57,7 @@
|
|||
'ec3_audio_util_unittest.cc',
|
||||
'h264_byte_to_unit_stream_converter_unittest.cc',
|
||||
'h264_parser_unittest.cc',
|
||||
'h265_byte_to_unit_stream_converter_unittest.cc',
|
||||
'h265_parser_unittest.cc',
|
||||
'h26x_bit_reader_unittest.cc',
|
||||
'hevc_decoder_configuration_unittest.cc',
|
||||
|
|
|
@ -15,74 +15,12 @@
|
|||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
namespace {
|
||||
// Additional space to reserve for output frame. This value ought to be enough
|
||||
// to acommodate frames consisting of 100 NAL units with 3-byte start codes.
|
||||
const size_t kStreamConversionOverhead = 100;
|
||||
}
|
||||
|
||||
H264ByteToUnitStreamConverter::H264ByteToUnitStreamConverter() {}
|
||||
|
||||
H264ByteToUnitStreamConverter::H264ByteToUnitStreamConverter()
|
||||
: H26xByteToUnitStreamConverter(NaluReader::kH264) {}
|
||||
H264ByteToUnitStreamConverter::~H264ByteToUnitStreamConverter() {}
|
||||
|
||||
bool H264ByteToUnitStreamConverter::ConvertByteStreamToNalUnitStream(
|
||||
const uint8_t* input_frame,
|
||||
size_t input_frame_size,
|
||||
std::vector<uint8_t>* output_frame) {
|
||||
DCHECK(input_frame);
|
||||
DCHECK(output_frame);
|
||||
|
||||
BufferWriter output_buffer(input_frame_size + kStreamConversionOverhead);
|
||||
|
||||
Nalu nalu;
|
||||
NaluReader reader(NaluReader::kH264, kIsAnnexbByteStream, input_frame,
|
||||
input_frame_size);
|
||||
if (!reader.StartsWithStartCode()) {
|
||||
LOG(ERROR) << "H.264 byte stream frame did not begin with start code.";
|
||||
return false;
|
||||
}
|
||||
while (reader.Advance(&nalu) == NaluReader::kOk) {
|
||||
ProcessNalu(nalu, &output_buffer);
|
||||
}
|
||||
|
||||
output_buffer.SwapBuffer(output_frame);
|
||||
return true;
|
||||
}
|
||||
|
||||
void H264ByteToUnitStreamConverter::ProcessNalu(const Nalu& nalu,
|
||||
BufferWriter* output_buffer) {
|
||||
DCHECK(nalu.data());
|
||||
DCHECK(output_buffer);
|
||||
|
||||
// Skip the start code, but keep the 1-byte NALU type.
|
||||
const uint8_t* nalu_ptr = nalu.data();
|
||||
const uint64_t nalu_size = nalu.payload_size() + nalu.header_size();
|
||||
DCHECK_LE(nalu_size, std::numeric_limits<uint32_t>::max());
|
||||
|
||||
switch (nalu.type()) {
|
||||
case Nalu::H264_SPS:
|
||||
// Grab SPS NALU.
|
||||
last_sps_.assign(nalu_ptr, nalu_ptr + nalu_size);
|
||||
return;
|
||||
case Nalu::H264_PPS:
|
||||
// Grab PPS NALU.
|
||||
last_pps_.assign(nalu_ptr, nalu_ptr + nalu_size);
|
||||
return;
|
||||
case Nalu::H264_AUD:
|
||||
// Ignore AUD NALU.
|
||||
return;
|
||||
default:
|
||||
// Copy all other NALUs.
|
||||
break;
|
||||
}
|
||||
|
||||
// Append 4-byte length and NAL unit data to the buffer.
|
||||
output_buffer->AppendInt(static_cast<uint32_t>(nalu_size));
|
||||
output_buffer->AppendArray(nalu_ptr, nalu_size);
|
||||
}
|
||||
|
||||
bool H264ByteToUnitStreamConverter::GetAVCDecoderConfigurationRecord(
|
||||
std::vector<uint8_t>* decoder_config) {
|
||||
bool H264ByteToUnitStreamConverter::GetDecoderConfigurationRecord(
|
||||
std::vector<uint8_t>* decoder_config) const {
|
||||
DCHECK(decoder_config);
|
||||
|
||||
if ((last_sps_.size() < 4) || last_pps_.empty()) {
|
||||
|
@ -108,10 +46,35 @@ bool H264ByteToUnitStreamConverter::GetAVCDecoderConfigurationRecord(
|
|||
buffer.AppendInt(num_pps);
|
||||
buffer.AppendInt(static_cast<uint16_t>(last_pps_.size()));
|
||||
buffer.AppendVector(last_pps_);
|
||||
buffer.SwapBuffer(decoder_config);
|
||||
|
||||
buffer.SwapBuffer(decoder_config);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool H264ByteToUnitStreamConverter::ProcessNalu(const Nalu& nalu) {
|
||||
DCHECK(nalu.data());
|
||||
|
||||
// Skip the start code, but keep the 1-byte NALU type.
|
||||
const uint8_t* nalu_ptr = nalu.data();
|
||||
const uint64_t nalu_size = nalu.payload_size() + nalu.header_size();
|
||||
|
||||
switch (nalu.type()) {
|
||||
case Nalu::H264_SPS:
|
||||
// Grab SPS NALU.
|
||||
last_sps_.assign(nalu_ptr, nalu_ptr + nalu_size);
|
||||
return true;
|
||||
case Nalu::H264_PPS:
|
||||
// Grab PPS NALU.
|
||||
last_pps_.assign(nalu_ptr, nalu_ptr + nalu_size);
|
||||
return true;
|
||||
case Nalu::H264_AUD:
|
||||
// Ignore AUD NALU.
|
||||
return true;
|
||||
default:
|
||||
// Have the base class handle other NALU types.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
||||
|
|
|
@ -12,46 +12,31 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include "packager/media/filters/h26x_byte_to_unit_stream_converter.h"
|
||||
|
||||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
class BufferWriter;
|
||||
class Nalu;
|
||||
|
||||
/// Class which converts H.264 byte streams (as specified in ISO/IEC 14496-10
|
||||
/// Annex B) into H.264 NAL unit streams (as specified in ISO/IEC 14496-15).
|
||||
class H264ByteToUnitStreamConverter {
|
||||
class H264ByteToUnitStreamConverter : public H26xByteToUnitStreamConverter {
|
||||
public:
|
||||
static const size_t kUnitStreamNaluLengthSize = 4;
|
||||
|
||||
H264ByteToUnitStreamConverter();
|
||||
~H264ByteToUnitStreamConverter();
|
||||
~H264ByteToUnitStreamConverter() override;
|
||||
|
||||
/// Converts a whole AVC byte stream encoded video frame to NAL unit stream
|
||||
/// format.
|
||||
/// @param input_frame is a buffer containing a whole H.264 frame in byte
|
||||
/// stream format.
|
||||
/// @param input_frame_size is the size of the H.264 frame, in bytes.
|
||||
/// @param output_frame is a pointer to a vector which will receive the
|
||||
/// converted frame.
|
||||
/// @return true if successful, false otherwise.
|
||||
bool ConvertByteStreamToNalUnitStream(const uint8_t* input_frame,
|
||||
size_t input_frame_size,
|
||||
std::vector<uint8_t>* output_frame);
|
||||
|
||||
/// Synthesizes an AVCDecoderConfigurationRecord from the SPS and PPS NAL
|
||||
/// units extracted from the AVC byte stream.
|
||||
/// @param decoder_config is a pointer to a vector, which on successful
|
||||
/// return will contain the computed AVCDecoderConfigurationRecord.
|
||||
/// @return true if successful, or false otherwise.
|
||||
bool GetAVCDecoderConfigurationRecord(std::vector<uint8_t>* decoder_config);
|
||||
/// @name H26xByteToUnitStreamConverter implementation override.
|
||||
/// @{
|
||||
bool GetDecoderConfigurationRecord(
|
||||
std::vector<uint8_t>* decoder_config) const override;
|
||||
/// @}
|
||||
|
||||
private:
|
||||
void ProcessNalu(const Nalu& nalu,
|
||||
BufferWriter* output_buffer);
|
||||
bool ProcessNalu(const Nalu& nalu) override;
|
||||
|
||||
std::vector<uint8_t> last_sps_;
|
||||
std::vector<uint8_t> last_pps_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(H264ByteToUnitStreamConverter);
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
|
|
|
@ -40,7 +40,7 @@ TEST(H264ByteToUnitStreamConverter, ConversionSuccess) {
|
|||
ASSERT_TRUE(base::HexStringToBytes(kExpectedConfigRecord,
|
||||
&expected_decoder_config));
|
||||
std::vector<uint8_t> decoder_config;
|
||||
ASSERT_TRUE(converter.GetAVCDecoderConfigurationRecord(&decoder_config));
|
||||
ASSERT_TRUE(converter.GetDecoderConfigurationRecord(&decoder_config));
|
||||
EXPECT_EQ(expected_decoder_config, decoder_config);
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ TEST(H264ByteToUnitStreamConverter, ConversionFailure) {
|
|||
input_frame.size(),
|
||||
&output_frame));
|
||||
std::vector<uint8_t> decoder_config;
|
||||
EXPECT_FALSE(converter.GetAVCDecoderConfigurationRecord(&decoder_config));
|
||||
EXPECT_FALSE(converter.GetDecoderConfigurationRecord(&decoder_config));
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include "packager/media/filters/h265_byte_to_unit_stream_converter.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "packager/base/logging.h"
|
||||
#include "packager/media/base/buffer_writer.h"
|
||||
#include "packager/media/base/rcheck.h"
|
||||
#include "packager/media/filters/h265_parser.h"
|
||||
|
||||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
H265ByteToUnitStreamConverter::H265ByteToUnitStreamConverter()
|
||||
: H26xByteToUnitStreamConverter(NaluReader::kH265) {}
|
||||
H265ByteToUnitStreamConverter::~H265ByteToUnitStreamConverter() {}
|
||||
|
||||
bool H265ByteToUnitStreamConverter::GetDecoderConfigurationRecord(
|
||||
std::vector<uint8_t>* decoder_config) const {
|
||||
DCHECK(decoder_config);
|
||||
|
||||
if (last_sps_.empty() || last_pps_.empty() || last_vps_.empty()) {
|
||||
// No data available to construct HEVCDecoderConfigurationRecord.
|
||||
return false;
|
||||
}
|
||||
|
||||
// We need to parse the SPS to get the data to add to the record.
|
||||
int id;
|
||||
Nalu nalu;
|
||||
H265Parser parser;
|
||||
RCHECK(nalu.InitializeFromH265(last_sps_.data(), last_sps_.size()));
|
||||
RCHECK(parser.ParseSps(nalu, &id) == H265Parser::kOk);
|
||||
const H265Sps* sps = parser.GetSps(id);
|
||||
|
||||
// Construct an HEVCDecoderConfigurationRecord containing a single SPS, PPS,
|
||||
// and VPS NALU. Please refer to ISO/IEC 14496-15 for format specifics.
|
||||
BufferWriter buffer(last_sps_.size() + last_pps_.size() + last_vps_.size() +
|
||||
100);
|
||||
buffer.AppendInt(static_cast<uint8_t>(1) /* version */);
|
||||
// (1) general_profile_space, general_tier_flag, general_profile_idc
|
||||
// (4) general_profile_compatibility_flags
|
||||
// (6) general_constraint_indicator_flags
|
||||
// (1) general_level_idc
|
||||
// Skip Nalu header (2) and the first byte of the SPS to get the
|
||||
// profile_tier_level.
|
||||
buffer.AppendArray(&last_sps_[2+1], 12);
|
||||
// min_spacial_segmentation_idc = 0 (Unknown)
|
||||
// TODO(modmaker): Parse vui_parameters and update this.
|
||||
buffer.AppendInt(static_cast<uint16_t>(0xf000));
|
||||
buffer.AppendInt(static_cast<uint8_t>(0xfc) /* parallelismType = 0 */);
|
||||
buffer.AppendInt(static_cast<uint8_t>(0xfc | sps->chroma_format_idc));
|
||||
buffer.AppendInt(static_cast<uint8_t>(0xf8 | sps->bit_depth_luma_minus8));
|
||||
buffer.AppendInt(static_cast<uint8_t>(0xf8 | sps->bit_depth_chroma_minus8));
|
||||
buffer.AppendInt(static_cast<uint16_t>(0) /* avgFrameRate */);
|
||||
// Following flags are 0:
|
||||
// constantFrameRate
|
||||
// numTemporalLayers
|
||||
// temporalIdNested
|
||||
buffer.AppendInt(static_cast<uint8_t>(kUnitStreamNaluLengthSize - 1));
|
||||
buffer.AppendInt(static_cast<uint8_t>(3) /* numOfArrays */);
|
||||
|
||||
// SPS
|
||||
const uint8_t kArrayCompleteness = 0x80;
|
||||
buffer.AppendInt(static_cast<uint8_t>(kArrayCompleteness | Nalu::H265_SPS));
|
||||
buffer.AppendInt(static_cast<uint16_t>(1) /* numNalus */);
|
||||
buffer.AppendInt(static_cast<uint16_t>(last_sps_.size()));
|
||||
buffer.AppendVector(last_sps_);
|
||||
|
||||
// PPS
|
||||
buffer.AppendInt(static_cast<uint8_t>(kArrayCompleteness | Nalu::H265_PPS));
|
||||
buffer.AppendInt(static_cast<uint16_t>(1) /* numNalus */);
|
||||
buffer.AppendInt(static_cast<uint16_t>(last_pps_.size()));
|
||||
buffer.AppendVector(last_pps_);
|
||||
|
||||
// VPS
|
||||
buffer.AppendInt(static_cast<uint8_t>(kArrayCompleteness | Nalu::H265_VPS));
|
||||
buffer.AppendInt(static_cast<uint16_t>(1) /* numNalus */);
|
||||
buffer.AppendInt(static_cast<uint16_t>(last_vps_.size()));
|
||||
buffer.AppendVector(last_vps_);
|
||||
|
||||
buffer.SwapBuffer(decoder_config);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool H265ByteToUnitStreamConverter::ProcessNalu(const Nalu& nalu) {
|
||||
DCHECK(nalu.data());
|
||||
|
||||
// Skip the start code, but keep the 2-byte NALU header.
|
||||
const uint8_t* nalu_ptr = nalu.data();
|
||||
const uint64_t nalu_size = nalu.payload_size() + nalu.header_size();
|
||||
|
||||
switch (nalu.type()) {
|
||||
case Nalu::H265_SPS:
|
||||
// Grab SPS NALU.
|
||||
last_sps_.assign(nalu_ptr, nalu_ptr + nalu_size);
|
||||
return true;
|
||||
case Nalu::H265_PPS:
|
||||
// Grab PPS NALU.
|
||||
last_pps_.assign(nalu_ptr, nalu_ptr + nalu_size);
|
||||
return true;
|
||||
case Nalu::H265_VPS:
|
||||
// Grab VPS NALU.
|
||||
last_vps_.assign(nalu_ptr, nalu_ptr + nalu_size);
|
||||
return true;
|
||||
case Nalu::H265_AUD:
|
||||
// Ignore AUD NALU.
|
||||
return true;
|
||||
default:
|
||||
// Have the base class handle other NALU types.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#ifndef MEDIA_FILTERS_H265_BYTE_TO_UNIT_STREAM_CONVERTER_H_
|
||||
#define MEDIA_FILTERS_H265_BYTE_TO_UNIT_STREAM_CONVERTER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "packager/media/filters/h26x_byte_to_unit_stream_converter.h"
|
||||
|
||||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
/// Class which converts H.265 byte streams (as specified in ISO/IEC 14496-10
|
||||
/// Annex B) into H.265 NAL unit streams (as specified in ISO/IEC 14496-15).
|
||||
class H265ByteToUnitStreamConverter : public H26xByteToUnitStreamConverter {
|
||||
public:
|
||||
H265ByteToUnitStreamConverter();
|
||||
~H265ByteToUnitStreamConverter() override;
|
||||
|
||||
/// @name H26xByteToUnitStreamConverter implementation override.
|
||||
/// @{
|
||||
bool GetDecoderConfigurationRecord(
|
||||
std::vector<uint8_t>* decoder_config) const override;
|
||||
/// @}
|
||||
|
||||
private:
|
||||
bool ProcessNalu(const Nalu& nalu) override;
|
||||
|
||||
std::vector<uint8_t> last_sps_;
|
||||
std::vector<uint8_t> last_pps_;
|
||||
std::vector<uint8_t> last_vps_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(H265ByteToUnitStreamConverter);
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
||||
|
||||
#endif // MEDIA_FILTERS_H265_BYTE_TO_UNIT_STREAM_CONVERTER_H_
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "packager/base/strings/string_number_conversions.h"
|
||||
#include "packager/media/filters/h265_byte_to_unit_stream_converter.h"
|
||||
#include "packager/media/filters/hevc_decoder_configuration.h"
|
||||
#include "packager/media/test/test_data_util.h"
|
||||
|
||||
namespace {
|
||||
const char kExpectedConfigRecord[] =
|
||||
"01016000000300900000030000f000fcfdf8f800000303a10001002e42010101600000"
|
||||
"030090000003000003005da0028080241f265999a4932bffc0d5c0d640400000030040"
|
||||
"00000602a2000100074401c172b46240a00001001840010c01ffff0160000003009000"
|
||||
"0003000003005d999809";
|
||||
}
|
||||
|
||||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
TEST(H265ByteToUnitStreamConverter, ConversionSuccess) {
|
||||
std::vector<uint8_t> input_frame =
|
||||
ReadTestDataFile("hevc-byte-stream-frame.h265");
|
||||
ASSERT_FALSE(input_frame.empty());
|
||||
|
||||
std::vector<uint8_t> expected_output_frame =
|
||||
ReadTestDataFile("hevc-unit-stream-frame.h265");
|
||||
ASSERT_FALSE(expected_output_frame.empty());
|
||||
|
||||
H265ByteToUnitStreamConverter converter;
|
||||
std::vector<uint8_t> output_frame;
|
||||
ASSERT_TRUE(converter.ConvertByteStreamToNalUnitStream(input_frame.data(),
|
||||
input_frame.size(),
|
||||
&output_frame));
|
||||
EXPECT_EQ(expected_output_frame, output_frame);
|
||||
|
||||
std::vector<uint8_t> expected_decoder_config;
|
||||
ASSERT_TRUE(base::HexStringToBytes(kExpectedConfigRecord,
|
||||
&expected_decoder_config));
|
||||
std::vector<uint8_t> decoder_config;
|
||||
ASSERT_TRUE(converter.GetDecoderConfigurationRecord(&decoder_config));
|
||||
EXPECT_EQ(expected_decoder_config, decoder_config);
|
||||
|
||||
// Double-check that it can be parsed.
|
||||
HEVCDecoderConfiguration conf;
|
||||
ASSERT_TRUE(conf.Parse(decoder_config));
|
||||
// The order is SPS, PPS, VPS.
|
||||
ASSERT_EQ(3u, conf.nalu_count());
|
||||
EXPECT_EQ(Nalu::H265_SPS, conf.nalu(0).type());
|
||||
EXPECT_EQ(Nalu::H265_PPS, conf.nalu(1).type());
|
||||
EXPECT_EQ(Nalu::H265_VPS, conf.nalu(2).type());
|
||||
}
|
||||
|
||||
TEST(H265ByteToUnitStreamConverter, ConversionFailure) {
|
||||
std::vector<uint8_t> input_frame(100, 0);
|
||||
|
||||
H265ByteToUnitStreamConverter converter;
|
||||
std::vector<uint8_t> output_frame;
|
||||
EXPECT_FALSE(converter.ConvertByteStreamToNalUnitStream(input_frame.data(),
|
||||
0,
|
||||
&output_frame));
|
||||
EXPECT_FALSE(converter.ConvertByteStreamToNalUnitStream(input_frame.data(),
|
||||
input_frame.size(),
|
||||
&output_frame));
|
||||
std::vector<uint8_t> decoder_config;
|
||||
EXPECT_FALSE(converter.GetDecoderConfigurationRecord(&decoder_config));
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include "packager/media/filters/h26x_byte_to_unit_stream_converter.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "packager/base/logging.h"
|
||||
#include "packager/media/base/buffer_writer.h"
|
||||
|
||||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
namespace {
|
||||
// Additional space to reserve for output frame. This value ought to be enough
|
||||
// to acommodate frames consisting of 100 NAL units with 3-byte start codes.
|
||||
const size_t kStreamConversionOverhead = 100;
|
||||
}
|
||||
|
||||
H26xByteToUnitStreamConverter::H26xByteToUnitStreamConverter(
|
||||
NaluReader::CodecType type)
|
||||
: type_(type) {}
|
||||
H26xByteToUnitStreamConverter::~H26xByteToUnitStreamConverter() {}
|
||||
|
||||
bool H26xByteToUnitStreamConverter::ConvertByteStreamToNalUnitStream(
|
||||
const uint8_t* input_frame,
|
||||
size_t input_frame_size,
|
||||
std::vector<uint8_t>* output_frame) {
|
||||
DCHECK(input_frame);
|
||||
DCHECK(output_frame);
|
||||
|
||||
BufferWriter output_buffer(input_frame_size + kStreamConversionOverhead);
|
||||
|
||||
Nalu nalu;
|
||||
NaluReader reader(type_, kIsAnnexbByteStream, input_frame, input_frame_size);
|
||||
if (!reader.StartsWithStartCode()) {
|
||||
LOG(ERROR) << "H.26x byte stream frame did not begin with start code.";
|
||||
return false;
|
||||
}
|
||||
|
||||
while (reader.Advance(&nalu) == NaluReader::kOk) {
|
||||
const uint64_t nalu_size = nalu.payload_size() + nalu.header_size();
|
||||
DCHECK_LE(nalu_size, std::numeric_limits<uint32_t>::max());
|
||||
|
||||
if (ProcessNalu(nalu))
|
||||
continue;
|
||||
|
||||
// Append 4-byte length and NAL unit data to the buffer.
|
||||
output_buffer.AppendInt(static_cast<uint32_t>(nalu_size));
|
||||
output_buffer.AppendArray(nalu.data(), nalu_size);
|
||||
}
|
||||
|
||||
output_buffer.SwapBuffer(output_frame);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#ifndef MEDIA_FILTERS_H26X_BYTE_TO_UNIT_STREAM_CONVERTER_H_
|
||||
#define MEDIA_FILTERS_H26X_BYTE_TO_UNIT_STREAM_CONVERTER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "packager/media/filters/nalu_reader.h"
|
||||
|
||||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
class BufferWriter;
|
||||
|
||||
/// A base class that is used to convert H.26x byte streams to NAL unit streams.
|
||||
class H26xByteToUnitStreamConverter {
|
||||
public:
|
||||
static const size_t kUnitStreamNaluLengthSize = 4;
|
||||
|
||||
H26xByteToUnitStreamConverter(NaluReader::CodecType type);
|
||||
virtual ~H26xByteToUnitStreamConverter();
|
||||
|
||||
/// Converts a whole byte stream encoded video frame to NAL unit stream
|
||||
/// format.
|
||||
/// @param input_frame is a buffer containing a whole H.26x frame in byte
|
||||
/// stream format.
|
||||
/// @param input_frame_size is the size of the H.26x frame, in bytes.
|
||||
/// @param output_frame is a pointer to a vector which will receive the
|
||||
/// converted frame.
|
||||
/// @return true if successful, false otherwise.
|
||||
bool ConvertByteStreamToNalUnitStream(const uint8_t* input_frame,
|
||||
size_t input_frame_size,
|
||||
std::vector<uint8_t>* output_frame);
|
||||
|
||||
/// Creates either an AVCDecoderConfigurationRecord or a
|
||||
/// HEVCDecoderConfigurationRecord from the units extracted from the byte
|
||||
/// stream.
|
||||
/// @param decoder_config is a pointer to a vector, which on successful
|
||||
/// return will contain the computed record.
|
||||
/// @return true if successful, or false otherwise.
|
||||
virtual bool GetDecoderConfigurationRecord(
|
||||
std::vector<uint8_t>* decoder_config) const = 0;
|
||||
|
||||
private:
|
||||
// Process the given Nalu. If this returns true, it was handled and should
|
||||
// not be copied to the buffer.
|
||||
virtual bool ProcessNalu(const Nalu& nalu) = 0;
|
||||
|
||||
NaluReader::CodecType type_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(H26xByteToUnitStreamConverter);
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
||||
|
||||
#endif // MEDIA_FILTERS_H26x_BYTE_TO_UNIT_STREAM_CONVERTER_H_
|
||||
|
|
@ -155,7 +155,7 @@ bool NalUnitToByteStreamConverter::ConvertUnitToByteStream(
|
|||
if (is_key_frame)
|
||||
buffer_writer.AppendVector(decoder_configuration_in_byte_stream_);
|
||||
|
||||
NaluReader nalu_reader(NaluReader::NaluType::kH264, nalu_length_size_, sample,
|
||||
NaluReader nalu_reader(NaluReader::kH264, nalu_length_size_, sample,
|
||||
sample_size);
|
||||
Nalu nalu;
|
||||
NaluReader::Result result = nalu_reader.Advance(&nalu);
|
||||
|
|
|
@ -142,7 +142,7 @@ bool Nalu::InitializeFromH265(const uint8_t* data, uint64_t size) {
|
|||
return true;
|
||||
}
|
||||
|
||||
NaluReader::NaluReader(NaluType type,
|
||||
NaluReader::NaluReader(CodecType type,
|
||||
uint8_t nal_length_size,
|
||||
const uint8_t* stream,
|
||||
uint64_t stream_size)
|
||||
|
|
|
@ -125,7 +125,7 @@ class NaluReader {
|
|||
kInvalidStream, // error in stream
|
||||
kEOStream, // end of stream
|
||||
};
|
||||
enum NaluType {
|
||||
enum CodecType {
|
||||
kH264,
|
||||
kH265,
|
||||
};
|
||||
|
@ -133,7 +133,7 @@ class NaluReader {
|
|||
/// @param nalu_length_size should be set to 0 for AnnexB byte streams;
|
||||
/// otherwise, it indicates the size of NAL unit length for the NAL
|
||||
/// unit stream.
|
||||
NaluReader(NaluType type,
|
||||
NaluReader(CodecType type,
|
||||
uint8_t nal_length_size,
|
||||
const uint8_t* stream,
|
||||
uint64_t stream_size);
|
||||
|
@ -183,7 +183,7 @@ class NaluReader {
|
|||
// The remaining size of the stream.
|
||||
uint64_t stream_size_;
|
||||
// The type of NALU being read.
|
||||
NaluType nalu_type_;
|
||||
CodecType nalu_type_;
|
||||
// The number of bytes the prefix length is; only valid if format is
|
||||
// kAnnexbByteStreamFormat.
|
||||
uint8_t nalu_length_size_;
|
||||
|
|
|
@ -329,7 +329,7 @@ bool EsParserH264::EmitFrame(int64_t access_unit_pos,
|
|||
|
||||
bool EsParserH264::UpdateVideoDecoderConfig(const H264Sps* sps) {
|
||||
std::vector<uint8_t> decoder_config_record;
|
||||
if (!stream_converter_->GetAVCDecoderConfigurationRecord(
|
||||
if (!stream_converter_->GetDecoderConfigurationRecord(
|
||||
&decoder_config_record)) {
|
||||
DLOG(ERROR) << "Failure to construct an AVCDecoderConfigurationRecord";
|
||||
return false;
|
||||
|
|
|
@ -238,7 +238,7 @@ Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {
|
|||
data += frame.frame_size;
|
||||
}
|
||||
} else {
|
||||
const NaluReader::NaluType nalu_type =
|
||||
const NaluReader::CodecType nalu_type =
|
||||
(video_codec_ == kCodecHVC1 || video_codec_ == kCodecHEV1)
|
||||
? NaluReader::kH265
|
||||
: NaluReader::kH264;
|
||||
|
|
|
@ -827,7 +827,7 @@ bool WvmMediaParser::Output(bool output_encrypted_sample) {
|
|||
// Set extra data for video stream from AVC Decoder Config Record.
|
||||
// Also, set codec string from the AVC Decoder Config Record.
|
||||
std::vector<uint8_t> decoder_config_record;
|
||||
byte_to_unit_stream_converter_.GetAVCDecoderConfigurationRecord(
|
||||
byte_to_unit_stream_converter_.GetDecoderConfigurationRecord(
|
||||
&decoder_config_record);
|
||||
for (uint32_t i = 0; i < stream_infos_.size(); i++) {
|
||||
if (stream_infos_[i]->stream_type() == media::kStreamVideo &&
|
||||
|
|
|
@ -87,3 +87,6 @@ bear_no_i_frame_start.h264
|
|||
|
||||
avc-byte-stream-frame.h264 - Single IDR frame extracted from test-25fps.h264 in Annex B byte stream format.
|
||||
avc-unit-stream-frame.h264 - Single IDR frame from avc-byte-stream-frame.h264 converted to unit stream format.
|
||||
|
||||
hevc-byte-stream-frame.h265 - Several video frames with SPS/PPS/VPS manually extracted from an H.265 stream, in Annex B byte stream format.
|
||||
hevc-byte-stream-frame.h265 - hevc-byte-stream-frame.h265 converted to unit stream format.
|
||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue