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