Allow generating avc3 / hev1 from TS and Wvm files
Added a flag --strip_parameter_set_nalus. When enabled, parameter set NAL units, SPS/PPS for H264 and SPS/PPS/VPS for H265, are stripped from frames when converting NAL byte stream (AnnexB stream) to NAL unit stream, which generates avc1/hvc1; otherwise they are not stripped, and avc3/hev1 is generated. Parameter set NAL units should not be stripped if they are varying in the frames otherwise the frames may fail to be decoded. The flag is enabled by default as we don't usually see varying SPS/PPS/VPS and it is more space efficient with them stripped. Set --strip_parameter_set_nalus=false to disable the flag if there are varying SPS/PPS/VPS in the frames. This addresses #206. Change-Id: I34bde6f33069f9f77d51a510b39f58a0f0e141aa
This commit is contained in:
parent
3d7635d5de
commit
277c5b23c0
|
@ -22,6 +22,7 @@ enum FourCC : uint32_t {
|
|||
FOURCC_ac_3 = 0x61632d33, // "ac-3"
|
||||
FOURCC_apad = 0x61706164,
|
||||
FOURCC_avc1 = 0x61766331,
|
||||
FOURCC_avc3 = 0x61766333,
|
||||
FOURCC_avcC = 0x61766343,
|
||||
FOURCC_bloc = 0x626C6F63,
|
||||
FOURCC_cbc1 = 0x63626331,
|
||||
|
|
|
@ -159,9 +159,10 @@ std::shared_ptr<StreamInfo> MediaHandlerTestBase::GetMockStreamInfo(
|
|||
!kEncrypted));
|
||||
} else if (codec >= kCodecVideo && codec < kCodecVideoMaxPlusOne) {
|
||||
return std::shared_ptr<StreamInfo>(new VideoStreamInfo(
|
||||
kTrackId, time_scale, kDuration, codec, kCodecString, kCodecConfig,
|
||||
sizeof(kCodecConfig), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, !kEncrypted));
|
||||
kTrackId, time_scale, kDuration, codec, H26xStreamFormat::kUnSpecified,
|
||||
kCodecString, kCodecConfig, sizeof(kCodecConfig), kWidth, kHeight,
|
||||
kPixelWidth, kPixelHeight, kTrickPlayRate, kNaluLengthSize, kLanguage,
|
||||
!kEncrypted));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -27,12 +27,7 @@ enum Codec {
|
|||
|
||||
kCodecVideo = 100,
|
||||
kCodecH264 = kCodecVideo,
|
||||
kCodecHEV1,
|
||||
kCodecHVC1,
|
||||
kCodecVC1,
|
||||
kCodecMPEG2,
|
||||
kCodecMPEG4,
|
||||
kCodecTheora,
|
||||
kCodecH265,
|
||||
kCodecVP8,
|
||||
kCodecVP9,
|
||||
kCodecVP10,
|
||||
|
@ -41,6 +36,8 @@ enum Codec {
|
|||
kCodecAudio = 200,
|
||||
kCodecAAC = kCodecAudio,
|
||||
kCodecAC3,
|
||||
// TODO(kqyang): Use kCodecDTS and a kDtsStreamFormat for the various DTS
|
||||
// streams.
|
||||
kCodecDTSC,
|
||||
kCodecDTSE,
|
||||
kCodecDTSH,
|
||||
|
|
|
@ -20,18 +20,8 @@ std::string VideoCodecToString(Codec codec) {
|
|||
switch (codec) {
|
||||
case kCodecH264:
|
||||
return "H264";
|
||||
case kCodecHEV1:
|
||||
return "HEV1";
|
||||
case kCodecHVC1:
|
||||
return "HVC1";
|
||||
case kCodecVC1:
|
||||
return "VC1";
|
||||
case kCodecMPEG2:
|
||||
return "MPEG2";
|
||||
case kCodecMPEG4:
|
||||
return "MPEG4";
|
||||
case kCodecTheora:
|
||||
return "Theora";
|
||||
case kCodecH265:
|
||||
return "H265";
|
||||
case kCodecVP8:
|
||||
return "VP8";
|
||||
case kCodecVP9:
|
||||
|
@ -46,15 +36,33 @@ std::string VideoCodecToString(Codec codec) {
|
|||
|
||||
} // namespace
|
||||
|
||||
VideoStreamInfo::VideoStreamInfo(
|
||||
int track_id, uint32_t time_scale, uint64_t duration, Codec codec,
|
||||
const std::string& codec_string, const uint8_t* codec_config,
|
||||
size_t codec_config_size, uint16_t width, uint16_t height,
|
||||
uint32_t pixel_width, uint32_t pixel_height, int16_t trick_play_rate,
|
||||
uint8_t nalu_length_size, const std::string& language, bool is_encrypted)
|
||||
: StreamInfo(kStreamVideo, track_id, time_scale, duration, codec,
|
||||
codec_string, codec_config, codec_config_size, language,
|
||||
VideoStreamInfo::VideoStreamInfo(int track_id,
|
||||
uint32_t time_scale,
|
||||
uint64_t duration,
|
||||
Codec codec,
|
||||
H26xStreamFormat h26x_stream_format,
|
||||
const std::string& codec_string,
|
||||
const uint8_t* codec_config,
|
||||
size_t codec_config_size,
|
||||
uint16_t width,
|
||||
uint16_t height,
|
||||
uint32_t pixel_width,
|
||||
uint32_t pixel_height,
|
||||
int16_t trick_play_rate,
|
||||
uint8_t nalu_length_size,
|
||||
const std::string& language,
|
||||
bool is_encrypted)
|
||||
: StreamInfo(kStreamVideo,
|
||||
track_id,
|
||||
time_scale,
|
||||
duration,
|
||||
codec,
|
||||
codec_string,
|
||||
codec_config,
|
||||
codec_config_size,
|
||||
language,
|
||||
is_encrypted),
|
||||
h26x_stream_format_(h26x_stream_format),
|
||||
width_(width),
|
||||
height_(height),
|
||||
pixel_width_(pixel_width),
|
||||
|
|
|
@ -12,18 +12,34 @@
|
|||
namespace shaka {
|
||||
namespace media {
|
||||
|
||||
enum class H26xStreamFormat {
|
||||
kUnSpecified,
|
||||
kAnnexbByteStream,
|
||||
kNalUnitStreamWithParameterSetNalus,
|
||||
kNalUnitStreamWithoutParameterSetNalus,
|
||||
};
|
||||
|
||||
/// Holds video stream information.
|
||||
class VideoStreamInfo : public StreamInfo {
|
||||
public:
|
||||
/// Construct an initialized video stream info object.
|
||||
/// @param pixel_width is the width of the pixel. 0 if unknown.
|
||||
/// @param pixel_height is the height of the pixels. 0 if unknown.
|
||||
VideoStreamInfo(int track_id, uint32_t time_scale, uint64_t duration,
|
||||
Codec codec, const std::string& codec_string,
|
||||
const uint8_t* codec_config, size_t codec_config_size,
|
||||
uint16_t width, uint16_t height, uint32_t pixel_width,
|
||||
uint32_t pixel_height, int16_t trick_play_rate,
|
||||
uint8_t nalu_length_size, const std::string& language,
|
||||
VideoStreamInfo(int track_id,
|
||||
uint32_t time_scale,
|
||||
uint64_t duration,
|
||||
Codec codec,
|
||||
H26xStreamFormat h26x_stream_format,
|
||||
const std::string& codec_string,
|
||||
const uint8_t* codec_config,
|
||||
size_t codec_config_size,
|
||||
uint16_t width,
|
||||
uint16_t height,
|
||||
uint32_t pixel_width,
|
||||
uint32_t pixel_height,
|
||||
int16_t trick_play_rate,
|
||||
uint8_t nalu_length_size,
|
||||
const std::string& language,
|
||||
bool is_encrypted);
|
||||
|
||||
~VideoStreamInfo() override;
|
||||
|
@ -34,6 +50,7 @@ class VideoStreamInfo : public StreamInfo {
|
|||
std::string ToString() const override;
|
||||
/// @}
|
||||
|
||||
H26xStreamFormat h26x_stream_format() const { return h26x_stream_format_; }
|
||||
uint16_t width() const { return width_; }
|
||||
uint16_t height() const { return height_; }
|
||||
/// Returns the pixel width.
|
||||
|
@ -56,6 +73,7 @@ class VideoStreamInfo : public StreamInfo {
|
|||
}
|
||||
|
||||
private:
|
||||
H26xStreamFormat h26x_stream_format_;
|
||||
uint16_t width_;
|
||||
uint16_t height_;
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
],
|
||||
'dependencies': [
|
||||
'../../base/base.gyp:base',
|
||||
'../../third_party/gflags/gflags.gyp:gflags',
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
@ -17,6 +17,11 @@ namespace media {
|
|||
|
||||
H264ByteToUnitStreamConverter::H264ByteToUnitStreamConverter()
|
||||
: H26xByteToUnitStreamConverter(Nalu::kH264) {}
|
||||
|
||||
H264ByteToUnitStreamConverter::H264ByteToUnitStreamConverter(
|
||||
H26xStreamFormat stream_format)
|
||||
: H26xByteToUnitStreamConverter(Nalu::kH264, stream_format) {}
|
||||
|
||||
H264ByteToUnitStreamConverter::~H264ByteToUnitStreamConverter() {}
|
||||
|
||||
bool H264ByteToUnitStreamConverter::GetDecoderConfigurationRecord(
|
||||
|
@ -60,13 +65,17 @@ bool H264ByteToUnitStreamConverter::ProcessNalu(const Nalu& nalu) {
|
|||
|
||||
switch (nalu.type()) {
|
||||
case Nalu::H264_SPS:
|
||||
if (strip_parameter_set_nalus())
|
||||
WarnIfNotMatch(nalu.type(), nalu_ptr, nalu_size, last_sps_);
|
||||
// Grab SPS NALU.
|
||||
last_sps_.assign(nalu_ptr, nalu_ptr + nalu_size);
|
||||
return true;
|
||||
return strip_parameter_set_nalus();
|
||||
case Nalu::H264_PPS:
|
||||
if (strip_parameter_set_nalus())
|
||||
WarnIfNotMatch(nalu.type(), nalu_ptr, nalu_size, last_pps_);
|
||||
// Grab PPS NALU.
|
||||
last_pps_.assign(nalu_ptr, nalu_ptr + nalu_size);
|
||||
return true;
|
||||
return strip_parameter_set_nalus();
|
||||
case Nalu::H264_AUD:
|
||||
// Ignore AUD NALU.
|
||||
return true;
|
||||
|
|
|
@ -21,7 +21,14 @@ namespace media {
|
|||
/// Annex B) into H.264 NAL unit streams (as specified in ISO/IEC 14496-15).
|
||||
class H264ByteToUnitStreamConverter : public H26xByteToUnitStreamConverter {
|
||||
public:
|
||||
/// Create a H264 byte to unit stream converter.
|
||||
/// The setting of @a KeepParameterSetNalus is defined by a gflag.
|
||||
H264ByteToUnitStreamConverter();
|
||||
|
||||
/// Create a H264 byte to unit stream converter with desired output stream
|
||||
/// format (whether to include parameter set nal units).
|
||||
explicit H264ByteToUnitStreamConverter(H26xStreamFormat stream_format);
|
||||
|
||||
~H264ByteToUnitStreamConverter() override;
|
||||
|
||||
/// @name H26xByteToUnitStreamConverter implementation override.
|
||||
|
|
|
@ -20,16 +20,17 @@ const char kExpectedConfigRecord[] =
|
|||
namespace shaka {
|
||||
namespace media {
|
||||
|
||||
TEST(H264ByteToUnitStreamConverter, ConversionSuccess) {
|
||||
TEST(H264ByteToUnitStreamConverter, StripParameterSetsNalu) {
|
||||
std::vector<uint8_t> input_frame =
|
||||
ReadTestDataFile("avc-byte-stream-frame.h264");
|
||||
ASSERT_FALSE(input_frame.empty());
|
||||
|
||||
std::vector<uint8_t> expected_output_frame =
|
||||
ReadTestDataFile("avc-unit-stream-frame.h264");
|
||||
ReadTestDataFile("avc1-unit-stream-frame.h264");
|
||||
ASSERT_FALSE(expected_output_frame.empty());
|
||||
|
||||
H264ByteToUnitStreamConverter converter;
|
||||
H264ByteToUnitStreamConverter converter(
|
||||
H26xStreamFormat::kNalUnitStreamWithoutParameterSetNalus);
|
||||
std::vector<uint8_t> output_frame;
|
||||
ASSERT_TRUE(converter.ConvertByteStreamToNalUnitStream(input_frame.data(),
|
||||
input_frame.size(),
|
||||
|
@ -44,10 +45,29 @@ TEST(H264ByteToUnitStreamConverter, ConversionSuccess) {
|
|||
EXPECT_EQ(expected_decoder_config, decoder_config);
|
||||
}
|
||||
|
||||
TEST(H264ByteToUnitStreamConverter, KeepParameterSetsNalu) {
|
||||
std::vector<uint8_t> input_frame =
|
||||
ReadTestDataFile("avc-byte-stream-frame.h264");
|
||||
ASSERT_FALSE(input_frame.empty());
|
||||
|
||||
std::vector<uint8_t> expected_output_frame =
|
||||
ReadTestDataFile("avc3-unit-stream-frame.h264");
|
||||
ASSERT_FALSE(expected_output_frame.empty());
|
||||
|
||||
H264ByteToUnitStreamConverter converter(
|
||||
H26xStreamFormat::kNalUnitStreamWithParameterSetNalus);
|
||||
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);
|
||||
}
|
||||
|
||||
TEST(H264ByteToUnitStreamConverter, ConversionFailure) {
|
||||
std::vector<uint8_t> input_frame(100, 0);
|
||||
|
||||
H264ByteToUnitStreamConverter converter;
|
||||
H264ByteToUnitStreamConverter converter(
|
||||
H26xStreamFormat::kNalUnitStreamWithParameterSetNalus);
|
||||
std::vector<uint8_t> output_frame;
|
||||
EXPECT_FALSE(converter.ConvertByteStreamToNalUnitStream(input_frame.data(),
|
||||
0,
|
||||
|
|
|
@ -18,6 +18,11 @@ namespace media {
|
|||
|
||||
H265ByteToUnitStreamConverter::H265ByteToUnitStreamConverter()
|
||||
: H26xByteToUnitStreamConverter(Nalu::kH265) {}
|
||||
|
||||
H265ByteToUnitStreamConverter::H265ByteToUnitStreamConverter(
|
||||
H26xStreamFormat stream_format)
|
||||
: H26xByteToUnitStreamConverter(Nalu::kH265, stream_format) {}
|
||||
|
||||
H265ByteToUnitStreamConverter::~H265ByteToUnitStreamConverter() {}
|
||||
|
||||
bool H265ByteToUnitStreamConverter::GetDecoderConfigurationRecord(
|
||||
|
@ -100,17 +105,23 @@ bool H265ByteToUnitStreamConverter::ProcessNalu(const Nalu& nalu) {
|
|||
|
||||
switch (nalu.type()) {
|
||||
case Nalu::H265_SPS:
|
||||
if (strip_parameter_set_nalus())
|
||||
WarnIfNotMatch(nalu.type(), nalu_ptr, nalu_size, last_sps_);
|
||||
// Grab SPS NALU.
|
||||
last_sps_.assign(nalu_ptr, nalu_ptr + nalu_size);
|
||||
return true;
|
||||
return strip_parameter_set_nalus();
|
||||
case Nalu::H265_PPS:
|
||||
if (strip_parameter_set_nalus())
|
||||
WarnIfNotMatch(nalu.type(), nalu_ptr, nalu_size, last_pps_);
|
||||
// Grab PPS NALU.
|
||||
last_pps_.assign(nalu_ptr, nalu_ptr + nalu_size);
|
||||
return true;
|
||||
return strip_parameter_set_nalus();
|
||||
case Nalu::H265_VPS:
|
||||
if (strip_parameter_set_nalus())
|
||||
WarnIfNotMatch(nalu.type(), nalu_ptr, nalu_size, last_vps_);
|
||||
// Grab VPS NALU.
|
||||
last_vps_.assign(nalu_ptr, nalu_ptr + nalu_size);
|
||||
return true;
|
||||
return strip_parameter_set_nalus();
|
||||
case Nalu::H265_AUD:
|
||||
// Ignore AUD NALU.
|
||||
return true;
|
||||
|
|
|
@ -21,7 +21,14 @@ namespace media {
|
|||
/// Annex B) into H.265 NAL unit streams (as specified in ISO/IEC 14496-15).
|
||||
class H265ByteToUnitStreamConverter : public H26xByteToUnitStreamConverter {
|
||||
public:
|
||||
/// Create a H265 byte to unit stream converter.
|
||||
/// The setting of @a KeepParameterSetNalus is defined by a gflag.
|
||||
H265ByteToUnitStreamConverter();
|
||||
|
||||
/// Create a H265 byte to unit stream converter with desired output stream
|
||||
/// format (whether to include parameter set nal units).
|
||||
explicit H265ByteToUnitStreamConverter(H26xStreamFormat stream_format);
|
||||
|
||||
~H265ByteToUnitStreamConverter() override;
|
||||
|
||||
/// @name H26xByteToUnitStreamConverter implementation override.
|
||||
|
|
|
@ -23,16 +23,17 @@ const char kExpectedConfigRecord[] =
|
|||
namespace shaka {
|
||||
namespace media {
|
||||
|
||||
TEST(H265ByteToUnitStreamConverter, ConversionSuccess) {
|
||||
TEST(H265ByteToUnitStreamConverter, StripParameterSetsNalu) {
|
||||
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");
|
||||
ReadTestDataFile("hvc1-unit-stream-frame.h265");
|
||||
ASSERT_FALSE(expected_output_frame.empty());
|
||||
|
||||
H265ByteToUnitStreamConverter converter;
|
||||
H265ByteToUnitStreamConverter converter(
|
||||
H26xStreamFormat::kNalUnitStreamWithoutParameterSetNalus);
|
||||
std::vector<uint8_t> output_frame;
|
||||
ASSERT_TRUE(converter.ConvertByteStreamToNalUnitStream(input_frame.data(),
|
||||
input_frame.size(),
|
||||
|
@ -56,10 +57,29 @@ TEST(H265ByteToUnitStreamConverter, ConversionSuccess) {
|
|||
EXPECT_EQ(Nalu::H265_VPS, config.nalu(2).type());
|
||||
}
|
||||
|
||||
TEST(H265ByteToUnitStreamConverter, KeepParameterSetsNalu) {
|
||||
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("hev1-unit-stream-frame.h265");
|
||||
ASSERT_FALSE(expected_output_frame.empty());
|
||||
|
||||
H265ByteToUnitStreamConverter converter(
|
||||
H26xStreamFormat::kNalUnitStreamWithParameterSetNalus);
|
||||
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);
|
||||
}
|
||||
|
||||
TEST(H265ByteToUnitStreamConverter, ConversionFailure) {
|
||||
std::vector<uint8_t> input_frame(100, 0);
|
||||
|
||||
H265ByteToUnitStreamConverter converter;
|
||||
H265ByteToUnitStreamConverter converter(
|
||||
H26xStreamFormat::kNalUnitStreamWithParameterSetNalus);
|
||||
std::vector<uint8_t> output_frame;
|
||||
EXPECT_FALSE(converter.ConvertByteStreamToNalUnitStream(input_frame.data(),
|
||||
0,
|
||||
|
|
|
@ -6,8 +6,21 @@
|
|||
|
||||
#include "packager/media/codecs/h26x_byte_to_unit_stream_converter.h"
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <limits>
|
||||
|
||||
#include "packager/base/strings/string_number_conversions.h"
|
||||
|
||||
// TODO(kqyang): Move byte to unit stream convertion to muxer and make it a
|
||||
// muxer option.
|
||||
DEFINE_bool(strip_parameter_set_nalus,
|
||||
true,
|
||||
"When converting from NAL byte stream (AnnexB stream) to NAL unit "
|
||||
"stream, this flag determines whether to strip parameter sets NAL "
|
||||
"units, i.e. SPS/PPS for H264 and SPS/PPS/VPS for H265, from the "
|
||||
"frames. Note that avc1/hvc1 is generated if this flag is enabled; "
|
||||
"otherwise avc3/hev1 is generated.");
|
||||
|
||||
#include "packager/base/logging.h"
|
||||
#include "packager/media/base/buffer_writer.h"
|
||||
|
||||
|
@ -22,7 +35,17 @@ const size_t kStreamConversionOverhead = 100;
|
|||
|
||||
H26xByteToUnitStreamConverter::H26xByteToUnitStreamConverter(
|
||||
Nalu::CodecType type)
|
||||
: type_(type) {}
|
||||
: type_(type),
|
||||
stream_format_(
|
||||
FLAGS_strip_parameter_set_nalus
|
||||
? H26xStreamFormat::kNalUnitStreamWithoutParameterSetNalus
|
||||
: H26xStreamFormat::kNalUnitStreamWithParameterSetNalus) {}
|
||||
|
||||
H26xByteToUnitStreamConverter::H26xByteToUnitStreamConverter(
|
||||
Nalu::CodecType type,
|
||||
H26xStreamFormat stream_format)
|
||||
: type_(type), stream_format_(stream_format) {}
|
||||
|
||||
H26xByteToUnitStreamConverter::~H26xByteToUnitStreamConverter() {}
|
||||
|
||||
bool H26xByteToUnitStreamConverter::ConvertByteStreamToNalUnitStream(
|
||||
|
@ -57,6 +80,22 @@ bool H26xByteToUnitStreamConverter::ConvertByteStreamToNalUnitStream(
|
|||
return true;
|
||||
}
|
||||
|
||||
void H26xByteToUnitStreamConverter::WarnIfNotMatch(
|
||||
int nalu_type,
|
||||
const uint8_t* nalu_ptr,
|
||||
size_t nalu_size,
|
||||
const std::vector<uint8_t>& vector) {
|
||||
if (vector.empty())
|
||||
return;
|
||||
if (vector.size() != nalu_size ||
|
||||
memcmp(vector.data(), nalu_ptr, nalu_size) != 0) {
|
||||
LOG(WARNING) << "Seeing varying NAL unit of type " << nalu_type
|
||||
<< ". You may need to set --strip_parameter_set_nalus=false "
|
||||
"during packaging to generate a playable stream.";
|
||||
VLOG(1) << "Old: " << base::HexEncode(vector.data(), vector.size());
|
||||
VLOG(1) << "New: " << base::HexEncode(nalu_ptr, nalu_size);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace shaka
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include "packager/media/base/video_stream_info.h"
|
||||
#include "packager/media/codecs/nalu_reader.h"
|
||||
|
||||
namespace shaka {
|
||||
|
@ -23,7 +24,15 @@ class H26xByteToUnitStreamConverter {
|
|||
public:
|
||||
static constexpr size_t kUnitStreamNaluLengthSize = 4;
|
||||
|
||||
/// Create a byte to unit stream converter with specified codec type.
|
||||
/// The setting of @a KeepParameterSetNalus is defined by a gflag.
|
||||
explicit H26xByteToUnitStreamConverter(Nalu::CodecType type);
|
||||
|
||||
/// Create a byte to unit stream converter with specified codec type and
|
||||
/// desired output stream format (whether to include parameter set nal units).
|
||||
H26xByteToUnitStreamConverter(Nalu::CodecType type,
|
||||
H26xStreamFormat stream_format);
|
||||
|
||||
virtual ~H26xByteToUnitStreamConverter();
|
||||
|
||||
/// Converts a whole byte stream encoded video frame to NAL unit stream
|
||||
|
@ -47,12 +56,27 @@ class H26xByteToUnitStreamConverter {
|
|||
virtual bool GetDecoderConfigurationRecord(
|
||||
std::vector<uint8_t>* decoder_config) const = 0;
|
||||
|
||||
H26xStreamFormat stream_format() const { return stream_format_; }
|
||||
|
||||
protected:
|
||||
bool strip_parameter_set_nalus() const {
|
||||
return stream_format_ ==
|
||||
H26xStreamFormat::kNalUnitStreamWithoutParameterSetNalus;
|
||||
}
|
||||
|
||||
// Warn if (nalu_ptr, nalu_size) does not match with |vector|.
|
||||
void WarnIfNotMatch(int nalu_type,
|
||||
const uint8_t* nalu_ptr,
|
||||
size_t nalu_size,
|
||||
const std::vector<uint8_t>& vector);
|
||||
|
||||
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;
|
||||
|
||||
Nalu::CodecType type_;
|
||||
H26xStreamFormat stream_format_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(H26xByteToUnitStreamConverter);
|
||||
};
|
||||
|
|
|
@ -59,18 +59,6 @@ std::string ReverseBitsAndHexEncode(uint32_t x) {
|
|||
return TrimLeadingZeros(base::HexEncode(bytes, arraysize(bytes)));
|
||||
}
|
||||
|
||||
std::string CodecAsString(Codec codec) {
|
||||
switch (codec) {
|
||||
case kCodecHEV1:
|
||||
return "hev1";
|
||||
case kCodecHVC1:
|
||||
return "hvc1";
|
||||
default:
|
||||
LOG(WARNING) << "Unknown codec: " << codec;
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
HEVCDecoderConfigurationRecord::HEVCDecoderConfigurationRecord()
|
||||
|
@ -132,10 +120,11 @@ bool HEVCDecoderConfigurationRecord::ParseInternal() {
|
|||
return true;
|
||||
}
|
||||
|
||||
std::string HEVCDecoderConfigurationRecord::GetCodecString(Codec codec) const {
|
||||
std::string HEVCDecoderConfigurationRecord::GetCodecString(
|
||||
FourCC codec_fourcc) const {
|
||||
// ISO/IEC 14496-15:2014 Annex E.
|
||||
std::vector<std::string> fields;
|
||||
fields.push_back(CodecAsString(codec));
|
||||
fields.push_back(FourCCToString(codec_fourcc));
|
||||
fields.push_back(GeneralProfileSpaceAsString(general_profile_space_) +
|
||||
base::IntToString(general_profile_idc_));
|
||||
fields.push_back(
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "packager/base/macros.h"
|
||||
#include "packager/media/base/fourccs.h"
|
||||
#include "packager/media/base/video_stream_info.h"
|
||||
#include "packager/media/codecs/decoder_configuration_record.h"
|
||||
|
||||
|
@ -25,7 +26,7 @@ class HEVCDecoderConfigurationRecord : public DecoderConfigurationRecord {
|
|||
~HEVCDecoderConfigurationRecord() override;
|
||||
|
||||
/// @return The codec string.
|
||||
std::string GetCodecString(Codec codec) const;
|
||||
std::string GetCodecString(FourCC codec_fourcc) const;
|
||||
|
||||
private:
|
||||
bool ParseInternal() override;
|
||||
|
|
|
@ -45,8 +45,8 @@ TEST(HEVCDecoderConfigurationRecordTest, Success) {
|
|||
|
||||
EXPECT_EQ(4u, hevc_config.nalu_length_size());
|
||||
|
||||
EXPECT_EQ("hev1.2.4.L63.90", hevc_config.GetCodecString(kCodecHEV1));
|
||||
EXPECT_EQ("hvc1.2.4.L63.90", hevc_config.GetCodecString(kCodecHVC1));
|
||||
EXPECT_EQ("hev1.2.4.L63.90", hevc_config.GetCodecString(FOURCC_hev1));
|
||||
EXPECT_EQ("hvc1.2.4.L63.90", hevc_config.GetCodecString(FOURCC_hvc1));
|
||||
|
||||
EXPECT_EQ(2u, hevc_config.nalu_count());
|
||||
EXPECT_EQ(0x16u, hevc_config.nalu(0).payload_size());
|
||||
|
|
|
@ -151,9 +151,7 @@ Status EncryptionHandler::ProcessStreamInfo(StreamInfo* stream_info) {
|
|||
case kCodecH264:
|
||||
header_parser_.reset(new H264VideoSliceHeaderParser);
|
||||
break;
|
||||
case kCodecHVC1:
|
||||
FALLTHROUGH_INTENDED;
|
||||
case kCodecHEV1:
|
||||
case kCodecH265:
|
||||
header_parser_.reset(new H265VideoSliceHeaderParser);
|
||||
break;
|
||||
default:
|
||||
|
@ -436,8 +434,7 @@ bool EncryptionHandler::EncryptNalFrame(MediaSample* sample,
|
|||
DCHECK_NE(nalu_length_size_, 0u);
|
||||
DCHECK(header_parser_);
|
||||
const Nalu::CodecType nalu_type =
|
||||
(codec_ == kCodecHVC1 || codec_ == kCodecHEV1) ? Nalu::kH265
|
||||
: Nalu::kH264;
|
||||
(codec_ == kCodecH265) ? Nalu::kH265 : Nalu::kH264;
|
||||
NaluReader reader(nalu_type, nalu_length_size_, sample->writable_data(),
|
||||
sample->data_size());
|
||||
|
||||
|
|
|
@ -18,8 +18,9 @@ std::shared_ptr<StreamInfo> CreateVideoStreamInfo(
|
|||
const VideoStreamInfoParameters& param) {
|
||||
return std::make_shared<VideoStreamInfo>(
|
||||
param.track_id, param.time_scale, param.duration, param.codec,
|
||||
param.codec_string, param.codec_config.data(), param.codec_config.size(),
|
||||
param.width, param.height, param.pixel_width, param.pixel_height,
|
||||
H26xStreamFormat::kUnSpecified, param.codec_string,
|
||||
param.codec_config.data(), param.codec_config.size(), param.width,
|
||||
param.height, param.pixel_width, param.pixel_height,
|
||||
0, // trick_play_rate
|
||||
param.nalu_length_size, param.language, param.is_encrypted);
|
||||
}
|
||||
|
|
|
@ -150,6 +150,7 @@ bool EsParserH264::UpdateVideoDecoderConfig(int pps_id) {
|
|||
H26xByteToUnitStreamConverter::kUnitStreamNaluLengthSize;
|
||||
last_video_decoder_config_ = std::make_shared<VideoStreamInfo>(
|
||||
pid(), kMpeg2Timescale, kInfiniteDuration, kCodecH264,
|
||||
stream_converter()->stream_format(),
|
||||
AVCDecoderConfigurationRecord::GetCodecString(decoder_config_record[1],
|
||||
decoder_config_record[2],
|
||||
decoder_config_record[3]),
|
||||
|
|
|
@ -153,9 +153,14 @@ bool EsParserH265::UpdateVideoDecoderConfig(int pps_id) {
|
|||
|
||||
const uint8_t nalu_length_size =
|
||||
H26xByteToUnitStreamConverter::kUnitStreamNaluLengthSize;
|
||||
const H26xStreamFormat stream_format = stream_converter()->stream_format();
|
||||
const FourCC codec_fourcc =
|
||||
stream_format == H26xStreamFormat::kNalUnitStreamWithParameterSetNalus
|
||||
? FOURCC_hev1
|
||||
: FOURCC_hvc1;
|
||||
last_video_decoder_config_ = std::make_shared<VideoStreamInfo>(
|
||||
pid(), kMpeg2Timescale, kInfiniteDuration, kCodecHVC1,
|
||||
decoder_config.GetCodecString(kCodecHVC1), decoder_config_record.data(),
|
||||
pid(), kMpeg2Timescale, kInfiniteDuration, kCodecH265, stream_format,
|
||||
decoder_config.GetCodecString(codec_fourcc), decoder_config_record.data(),
|
||||
decoder_config_record.size(), coded_width, coded_height, pixel_width,
|
||||
pixel_height, 0, nalu_length_size, std::string(), false);
|
||||
|
||||
|
|
|
@ -115,7 +115,8 @@ class MockAACAudioSpecificConfig : public AACAudioSpecificConfig {
|
|||
|
||||
std::shared_ptr<VideoStreamInfo> CreateVideoStreamInfo(Codec codec) {
|
||||
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||
kTrackId, kTimeScale, kDuration, codec, kCodecString, kVideoExtraData,
|
||||
kTrackId, kTimeScale, kDuration, codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kVideoExtraData,
|
||||
arraysize(kVideoExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
return stream_info;
|
||||
|
@ -344,9 +345,10 @@ TEST_F(PesPacketGeneratorTest, AddAudioSampleFailedToConvert) {
|
|||
TEST_F(PesPacketGeneratorTest, TimeStampScaling) {
|
||||
const uint32_t kTestTimescale = 1000;
|
||||
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||
kTrackId, kTestTimescale, kDuration, kH264Codec, kCodecString,
|
||||
kVideoExtraData, arraysize(kVideoExtraData), kWidth, kHeight, kPixelWidth,
|
||||
kPixelHeight, kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
kTrackId, kTestTimescale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kVideoExtraData,
|
||||
arraysize(kVideoExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
EXPECT_TRUE(generator_.Initialize(*stream_info));
|
||||
|
||||
EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets());
|
||||
|
|
|
@ -97,7 +97,8 @@ class TsSegmenterTest : public ::testing::Test {
|
|||
|
||||
TEST_F(TsSegmenterTest, Initialize) {
|
||||
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
MuxerOptions options;
|
||||
|
@ -117,7 +118,8 @@ TEST_F(TsSegmenterTest, Initialize) {
|
|||
|
||||
TEST_F(TsSegmenterTest, AddSample) {
|
||||
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
MuxerOptions options;
|
||||
|
@ -168,9 +170,10 @@ TEST_F(TsSegmenterTest, PassedSegmentDuration) {
|
|||
// done correctly in the segmenter.
|
||||
const uint32_t kInputTimescale = 1001;
|
||||
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||
kTrackId, kInputTimescale, kDuration, kH264Codec, kCodecString,
|
||||
kExtraData, arraysize(kExtraData), kWidth, kHeight, kPixelWidth,
|
||||
kPixelHeight, kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
kTrackId, kInputTimescale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
MuxerOptions options;
|
||||
options.segment_template = "file$Number$.ts";
|
||||
|
||||
|
@ -262,7 +265,8 @@ TEST_F(TsSegmenterTest, PassedSegmentDuration) {
|
|||
// Finalize right after Initialize(). The writer will not be initialized.
|
||||
TEST_F(TsSegmenterTest, InitializeThenFinalize) {
|
||||
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
MuxerOptions options;
|
||||
|
@ -290,7 +294,8 @@ TEST_F(TsSegmenterTest, InitializeThenFinalize) {
|
|||
// writer with a mock.
|
||||
TEST_F(TsSegmenterTest, FinalizeSegment) {
|
||||
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
MuxerOptions options;
|
||||
|
@ -317,7 +322,8 @@ TEST_F(TsSegmenterTest, FinalizeSegment) {
|
|||
|
||||
TEST_F(TsSegmenterTest, EncryptedSample) {
|
||||
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
MuxerOptions options;
|
||||
|
|
|
@ -158,7 +158,8 @@ class TsWriterTest : public ::testing::Test {
|
|||
|
||||
TEST_F(TsWriterTest, InitializeVideoH264) {
|
||||
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
|
||||
|
@ -166,9 +167,10 @@ TEST_F(TsWriterTest, InitializeVideoH264) {
|
|||
|
||||
TEST_F(TsWriterTest, InitializeVideoNonH264) {
|
||||
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||
kTrackId, kTimeScale, kDuration, Codec::kCodecVP9, kCodecString,
|
||||
kExtraData, arraysize(kExtraData), kWidth, kHeight, kPixelWidth,
|
||||
kPixelHeight, kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
kTrackId, kTimeScale, kDuration, Codec::kCodecVP9,
|
||||
H26xStreamFormat::kUnSpecified, kCodecString, kExtraData,
|
||||
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
EXPECT_FALSE(ts_writer_.Initialize(*stream_info));
|
||||
}
|
||||
|
||||
|
@ -199,7 +201,8 @@ TEST_F(TsWriterTest, ClearH264Psi) {
|
|||
EXPECT_CALL(*mock_pmt_writer, ClearSegmentPmt(_)).WillOnce(WriteOnePmt());
|
||||
|
||||
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
|
||||
|
@ -281,7 +284,8 @@ TEST_F(TsWriterTest, ClearLeadH264Pmt) {
|
|||
.WillOnce(WriteTwoPmts());
|
||||
|
||||
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
|
||||
|
@ -310,7 +314,8 @@ TEST_F(TsWriterTest, EncryptedSegmentsH264Pmt) {
|
|||
EXPECT_CALL(*mock_pmt_writer, EncryptedSegmentPmt(_)).WillOnce(WriteOnePmt());
|
||||
|
||||
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
|
||||
|
@ -398,7 +403,8 @@ TEST_F(TsWriterTest, EncryptedSegmentsAacPmt) {
|
|||
|
||||
TEST_F(TsWriterTest, AddPesPacket) {
|
||||
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
|
||||
|
@ -463,7 +469,8 @@ TEST_F(TsWriterTest, AddPesPacket) {
|
|||
// Verify that PES packet > 64KiB can be handled.
|
||||
TEST_F(TsWriterTest, BigPesPacket) {
|
||||
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
|
||||
|
@ -499,7 +506,8 @@ TEST_F(TsWriterTest, BigPesPacket) {
|
|||
// PTS (implicilty) cast to bool is true.
|
||||
TEST_F(TsWriterTest, PesPtsZeroNoDts) {
|
||||
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
|
||||
|
@ -559,7 +567,8 @@ TEST_F(TsWriterTest, PesPtsZeroNoDts) {
|
|||
// adaptation_field_length should be 0.
|
||||
TEST_F(TsWriterTest, TsPacketPayload183Bytes) {
|
||||
std::shared_ptr<VideoStreamInfo> stream_info(new VideoStreamInfo(
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec, kCodecString, kExtraData,
|
||||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
arraysize(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
EXPECT_TRUE(ts_writer_.Initialize(*stream_info));
|
||||
|
|
|
@ -1509,6 +1509,7 @@ bool VideoSampleEntry::ReadWriteInternal(BoxBuffer* buffer) {
|
|||
const FourCC actual_format = GetActualFormat();
|
||||
switch (actual_format) {
|
||||
case FOURCC_avc1:
|
||||
case FOURCC_avc3:
|
||||
compressor_name.assign(
|
||||
kAvcCompressorName,
|
||||
kAvcCompressorName + arraysize(kAvcCompressorName));
|
||||
|
@ -1595,6 +1596,7 @@ size_t VideoSampleEntry::ComputeSizeInternal() {
|
|||
FourCC VideoSampleEntry::GetCodecConfigurationBoxType(FourCC format) const {
|
||||
switch (format) {
|
||||
case FOURCC_avc1:
|
||||
case FOURCC_avc3:
|
||||
return FOURCC_avcC;
|
||||
case FOURCC_hev1:
|
||||
case FOURCC_hvc1:
|
||||
|
|
|
@ -40,14 +40,29 @@ uint64_t Rescale(uint64_t time_in_old_scale,
|
|||
return (static_cast<double>(time_in_old_scale) / old_scale) * new_scale;
|
||||
}
|
||||
|
||||
H26xStreamFormat GetH26xStreamFormat(FourCC fourcc) {
|
||||
switch (fourcc) {
|
||||
case FOURCC_avc1:
|
||||
return H26xStreamFormat::kNalUnitStreamWithoutParameterSetNalus;
|
||||
case FOURCC_avc3:
|
||||
return H26xStreamFormat::kNalUnitStreamWithParameterSetNalus;
|
||||
case FOURCC_hev1:
|
||||
return H26xStreamFormat::kNalUnitStreamWithParameterSetNalus;
|
||||
case FOURCC_hvc1:
|
||||
return H26xStreamFormat::kNalUnitStreamWithoutParameterSetNalus;
|
||||
default:
|
||||
return H26xStreamFormat::kUnSpecified;
|
||||
}
|
||||
}
|
||||
|
||||
Codec FourCCToCodec(FourCC fourcc) {
|
||||
switch (fourcc) {
|
||||
case FOURCC_avc1:
|
||||
case FOURCC_avc3:
|
||||
return kCodecH264;
|
||||
case FOURCC_hev1:
|
||||
return kCodecHEV1;
|
||||
case FOURCC_hvc1:
|
||||
return kCodecHVC1;
|
||||
return kCodecH265;
|
||||
case FOURCC_vp08:
|
||||
return kCodecVP8;
|
||||
case FOURCC_vp09:
|
||||
|
@ -497,7 +512,8 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
|
|||
const FourCC actual_format = entry.GetActualFormat();
|
||||
const Codec video_codec = FourCCToCodec(actual_format);
|
||||
switch (actual_format) {
|
||||
case FOURCC_avc1: {
|
||||
case FOURCC_avc1:
|
||||
case FOURCC_avc3: {
|
||||
AVCDecoderConfigurationRecord avc_config;
|
||||
if (!avc_config.Parse(entry.codec_configuration.data)) {
|
||||
LOG(ERROR) << "Failed to parse avcc.";
|
||||
|
@ -540,7 +556,7 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
|
|||
LOG(ERROR) << "Failed to parse hevc.";
|
||||
return false;
|
||||
}
|
||||
codec_string = hevc_config.GetCodecString(video_codec);
|
||||
codec_string = hevc_config.GetCodecString(actual_format);
|
||||
nalu_length_size = hevc_config.nalu_length_size();
|
||||
break;
|
||||
}
|
||||
|
@ -569,7 +585,8 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
|
|||
DVLOG(1) << "is_video_track_encrypted_: " << is_encrypted;
|
||||
std::shared_ptr<VideoStreamInfo> video_stream_info(new VideoStreamInfo(
|
||||
track->header.track_id, timescale, duration, video_codec,
|
||||
codec_string, entry.codec_configuration.data.data(),
|
||||
GetH26xStreamFormat(actual_format), codec_string,
|
||||
entry.codec_configuration.data.data(),
|
||||
entry.codec_configuration.data.size(), coded_width, coded_height,
|
||||
pixel_width, pixel_height,
|
||||
0, // trick_play_rate
|
||||
|
|
|
@ -39,14 +39,18 @@ void SetStartAndEndFromOffsetAndSize(size_t offset,
|
|||
*end = *start + static_cast<uint32_t>(size) - 1;
|
||||
}
|
||||
|
||||
FourCC CodecToFourCC(Codec codec) {
|
||||
FourCC CodecToFourCC(Codec codec, H26xStreamFormat h26x_stream_format) {
|
||||
switch (codec) {
|
||||
case kCodecH264:
|
||||
return FOURCC_avc1;
|
||||
case kCodecHEV1:
|
||||
return FOURCC_hev1;
|
||||
case kCodecHVC1:
|
||||
return FOURCC_hvc1;
|
||||
return h26x_stream_format ==
|
||||
H26xStreamFormat::kNalUnitStreamWithParameterSetNalus
|
||||
? FOURCC_avc3
|
||||
: FOURCC_avc1;
|
||||
case kCodecH265:
|
||||
return h26x_stream_format ==
|
||||
H26xStreamFormat::kNalUnitStreamWithParameterSetNalus
|
||||
? FOURCC_hev1
|
||||
: FOURCC_hvc1;
|
||||
case kCodecVP8:
|
||||
return FOURCC_vp08;
|
||||
case kCodecVP9:
|
||||
|
@ -115,7 +119,8 @@ Status MP4Muxer::InitializeMuxer() {
|
|||
ftyp->compatible_brands.push_back(FOURCC_mp41);
|
||||
if (streams().size() == 1 && streams()[0]->stream_type() == kStreamVideo) {
|
||||
const FourCC codec_fourcc = CodecToFourCC(
|
||||
static_cast<VideoStreamInfo*>(streams()[0].get())->codec());
|
||||
streams()[0]->codec(), static_cast<VideoStreamInfo*>(streams()[0].get())
|
||||
->h26x_stream_format());
|
||||
if (codec_fourcc != FOURCC_NULL)
|
||||
ftyp->compatible_brands.push_back(codec_fourcc);
|
||||
}
|
||||
|
@ -250,7 +255,8 @@ void MP4Muxer::GenerateVideoTrak(const VideoStreamInfo* video_info,
|
|||
trak->header.height = video_info->height() * 0x10000;
|
||||
|
||||
VideoSampleEntry video;
|
||||
video.format = CodecToFourCC(video_info->codec());
|
||||
video.format =
|
||||
CodecToFourCC(video_info->codec(), video_info->h26x_stream_format());
|
||||
video.width = video_info->width();
|
||||
video.height = video_info->height();
|
||||
video.codec_configuration.data = video_info->codec_config();
|
||||
|
@ -282,7 +288,8 @@ void MP4Muxer::GenerateAudioTrak(const AudioStreamInfo* audio_info,
|
|||
trak->header.volume = 0x100;
|
||||
|
||||
AudioSampleEntry audio;
|
||||
audio.format = CodecToFourCC(audio_info->codec());
|
||||
audio.format =
|
||||
CodecToFourCC(audio_info->codec(), H26xStreamFormat::kUnSpecified);
|
||||
switch(audio_info->codec()){
|
||||
case kCodecAAC:
|
||||
audio.esds.es_descriptor.set_object_type(kISO_14496_3); // MPEG4 AAC.
|
||||
|
|
|
@ -83,9 +83,9 @@ MuxerOptions SegmentTestBase::CreateMuxerOptions() const {
|
|||
|
||||
VideoStreamInfo* SegmentTestBase::CreateVideoStreamInfo() const {
|
||||
return new VideoStreamInfo(kTrackId, kTimeScale, kDuration, kCodec,
|
||||
kCodecString, NULL, 0, kWidth, kHeight,
|
||||
kPixelWidth, kPixelHeight, kTrickPlayRate,
|
||||
kNaluLengthSize, kLanguage, false);
|
||||
H26xStreamFormat::kUnSpecified, kCodecString, NULL,
|
||||
0, kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTrickPlayRate, kNaluLengthSize, kLanguage, false);
|
||||
}
|
||||
|
||||
std::string SegmentTestBase::OutputFileName() const {
|
||||
|
|
|
@ -322,16 +322,38 @@ bool VerifyTextBuffers(const BlockInfo* block_info_ptr,
|
|||
class WebMClusterParserTest : public testing::Test {
|
||||
public:
|
||||
WebMClusterParserTest()
|
||||
: audio_stream_info_(new AudioStreamInfo(
|
||||
kAudioTrackNum, kTimeScale, kDuration, kUnknownCodec, kCodecString,
|
||||
kExtraData, kExtraDataSize, kBitsPerSample, kNumChannels,
|
||||
kSamplingFrequency, kSeekPreroll, kCodecDelay, 0, 0, kLanguage,
|
||||
!kEncrypted)),
|
||||
video_stream_info_(new VideoStreamInfo(
|
||||
kVideoTrackNum, kTimeScale, kDuration, kCodecVP8, kCodecString,
|
||||
kExtraData, kExtraDataSize, kWidth, kHeight, kPixelWidth,
|
||||
kPixelHeight, kTrickPlayRate, kNaluLengthSize, kLanguage,
|
||||
!kEncrypted)),
|
||||
: audio_stream_info_(new AudioStreamInfo(kAudioTrackNum,
|
||||
kTimeScale,
|
||||
kDuration,
|
||||
kUnknownCodec,
|
||||
kCodecString,
|
||||
kExtraData,
|
||||
kExtraDataSize,
|
||||
kBitsPerSample,
|
||||
kNumChannels,
|
||||
kSamplingFrequency,
|
||||
kSeekPreroll,
|
||||
kCodecDelay,
|
||||
0,
|
||||
0,
|
||||
kLanguage,
|
||||
!kEncrypted)),
|
||||
video_stream_info_(new VideoStreamInfo(kVideoTrackNum,
|
||||
kTimeScale,
|
||||
kDuration,
|
||||
kCodecVP8,
|
||||
H26xStreamFormat::kUnSpecified,
|
||||
kCodecString,
|
||||
kExtraData,
|
||||
kExtraDataSize,
|
||||
kWidth,
|
||||
kHeight,
|
||||
kPixelWidth,
|
||||
kPixelHeight,
|
||||
kTrickPlayRate,
|
||||
kNaluLengthSize,
|
||||
kLanguage,
|
||||
!kEncrypted)),
|
||||
parser_(CreateDefaultParser()) {}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -109,9 +109,10 @@ std::shared_ptr<VideoStreamInfo> WebMVideoClient::GetVideoStreamInfo(
|
|||
sar_y /= gcd;
|
||||
|
||||
return std::make_shared<VideoStreamInfo>(
|
||||
track_num, kWebMTimeScale, 0, video_codec, std::string(),
|
||||
codec_private.data(), codec_private.size(), width_after_crop,
|
||||
height_after_crop, sar_x, sar_y, 0, 0, std::string(), is_encrypted);
|
||||
track_num, kWebMTimeScale, 0, video_codec, H26xStreamFormat::kUnSpecified,
|
||||
std::string(), codec_private.data(), codec_private.size(),
|
||||
width_after_crop, height_after_crop, sar_x, sar_y, 0, 0, std::string(),
|
||||
is_encrypted);
|
||||
}
|
||||
|
||||
bool WebMVideoClient::OnUInt(int id, int64_t val) {
|
||||
|
|
|
@ -108,8 +108,7 @@ WvmMediaParser::WvmMediaParser()
|
|||
media_sample_(NULL),
|
||||
crypto_unit_start_pos_(0),
|
||||
stream_id_count_(0),
|
||||
decryption_key_source_(NULL) {
|
||||
}
|
||||
decryption_key_source_(NULL) {}
|
||||
|
||||
WvmMediaParser::~WvmMediaParser() {}
|
||||
|
||||
|
@ -250,6 +249,7 @@ bool WvmMediaParser::Parse(const uint8_t* buf, int size) {
|
|||
if (HAS_HEADER_EXTENSION(pes_stream_id_)) {
|
||||
parse_state_ = PesExtension1;
|
||||
} else {
|
||||
prev_pes_flags_1_ = pes_flags_1_;
|
||||
pes_flags_1_ = pes_flags_2_ = 0;
|
||||
pes_header_data_bytes_ = 0;
|
||||
parse_state_ = PesPayload;
|
||||
|
@ -739,11 +739,11 @@ bool WvmMediaParser::ParseIndexEntry() {
|
|||
index_size = read_ptr - index_data_.data();
|
||||
|
||||
if (has_video) {
|
||||
Codec video_codec = kCodecH264;
|
||||
stream_infos_.emplace_back(new VideoStreamInfo(
|
||||
stream_id_count_, time_scale, track_duration, video_codec,
|
||||
std::string(), video_codec_config.data(), video_codec_config.size(),
|
||||
video_width, video_height, pixel_width, pixel_height, trick_play_rate,
|
||||
stream_id_count_, time_scale, track_duration, kCodecH264,
|
||||
byte_to_unit_stream_converter_.stream_format(), std::string(),
|
||||
video_codec_config.data(), video_codec_config.size(), video_width,
|
||||
video_height, pixel_width, pixel_height, trick_play_rate,
|
||||
nalu_length_size, std::string(),
|
||||
decryption_key_source_ ? false : true));
|
||||
program_demux_stream_map_[base::UintToString(index_program_id_) + ":" +
|
||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue