diff --git a/packager/media/base/media_base.gyp b/packager/media/base/media_base.gyp index 0843f2761a..71171a1a6f 100644 --- a/packager/media/base/media_base.gyp +++ b/packager/media/base/media_base.gyp @@ -108,6 +108,8 @@ 'timestamp.h', 'video_stream_info.cc', 'video_stream_info.h', + 'video_util.cc', + 'video_util.h', 'widevine_key_source.cc', 'widevine_key_source.h', 'widevine_pssh_generator.cc', @@ -188,6 +190,7 @@ 'test/fake_prng.h', # For rsa_key_unittest 'test/rsa_test_data.cc', # For rsa_key_unittest 'test/rsa_test_data.h', # For rsa_key_unittest + 'video_util_unittest.cc', 'widevine_key_source_unittest.cc', ], 'dependencies': [ diff --git a/packager/media/base/video_util.cc b/packager/media/base/video_util.cc new file mode 100644 index 0000000000..0f2c794739 --- /dev/null +++ b/packager/media/base/video_util.cc @@ -0,0 +1,68 @@ +// Copyright 2019 Google LLC. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "packager/media/base/video_util.h" + +#include + +namespace { + +uint64_t CalculateGCD(uint64_t a, uint64_t b) { + while (b != 0) { + uint64_t temp = a; + a = b; + b = temp % b; + } + return a; +} + +void ReducePixelWidthHeight(uint64_t* pixel_width, uint64_t* pixel_height) { + if (*pixel_width == 0 || *pixel_height == 0) + return; + const uint64_t kMaxUint32 = std::numeric_limits::max(); + while (true) { + uint64_t gcd = CalculateGCD(*pixel_width, *pixel_height); + *pixel_width /= gcd; + *pixel_height /= gcd; + // Both width and height needs to be 32 bit or less. + if (*pixel_width <= kMaxUint32 && *pixel_height <= kMaxUint32) + break; + *pixel_width >>= 1; + *pixel_height >>= 1; + } +} + +} // namespace + +namespace shaka { +namespace media { + +void DerivePixelWidthHeight(uint32_t frame_width, + uint32_t frame_height, + uint32_t display_width, + uint32_t display_height, + uint32_t* pixel_width, + uint32_t* pixel_height) { + // DAR = PAR * FAR => PAR = DAR / FAR. + // Thus: + // pixel_width display_width frame_width + // ----------- = ------------- / ----------- + // pixel_height display_height frame_height + // So: + // pixel_width display_width x frame_height + // ----------- = ------------------------------ + // pixel_height display_height x frame_width + uint64_t pixel_width_unreduced = + static_cast(display_width) * frame_height; + uint64_t pixel_height_unreduced = + static_cast(display_height) * frame_width; + ReducePixelWidthHeight(&pixel_width_unreduced, &pixel_height_unreduced); + *pixel_width = pixel_width_unreduced; + *pixel_height = pixel_height_unreduced; +} + +} // namespace media +} // namespace shaka diff --git a/packager/media/base/video_util.h b/packager/media/base/video_util.h new file mode 100644 index 0000000000..7ff81692c3 --- /dev/null +++ b/packager/media/base/video_util.h @@ -0,0 +1,26 @@ +// Copyright 2019 Google LLC. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef PACKAGER_MEDIA_BASE_VIDEO_UTIL_H_ +#define PACKAGER_MEDIA_BASE_VIDEO_UTIL_H_ + +#include + +namespace shaka { +namespace media { + +// Derive pixel aspect ratio from Display Aspect Ratio and Frame Aspect Ratio. +void DerivePixelWidthHeight(uint32_t frame_width, + uint32_t frame_height, + uint32_t display_width, + uint32_t display_height, + uint32_t* pixel_width, + uint32_t* pixel_height); + +} // namespace media +} // namespace shaka + +#endif // PACKAGER_MEDIA_BASE_VIDEO_UTIL_H_ diff --git a/packager/media/base/video_util_unittest.cc b/packager/media/base/video_util_unittest.cc new file mode 100644 index 0000000000..c1708ffd0f --- /dev/null +++ b/packager/media/base/video_util_unittest.cc @@ -0,0 +1,49 @@ +// Copyright 2019 Google LLC. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "packager/media/base/video_util.h" + +#include + +using ::testing::TestWithParam; +using ::testing::Values; + +namespace shaka { +namespace media { + +struct SarTestData { + uint32_t frame_width; + uint32_t frame_height; + uint32_t display_width; + uint32_t display_height; + uint32_t expected_pixel_width; + uint32_t expected_pixel_height; +}; + +class VideoUtilSarTest : public TestWithParam {}; + +TEST_P(VideoUtilSarTest, Test) { + const SarTestData& test_data = GetParam(); + + uint32_t pixel_width; + uint32_t pixel_height; + DerivePixelWidthHeight(test_data.frame_width, test_data.frame_height, + test_data.display_width, test_data.display_height, + &pixel_width, &pixel_height); + EXPECT_EQ(pixel_width, test_data.expected_pixel_width); + EXPECT_EQ(pixel_height, test_data.expected_pixel_height); +} + +INSTANTIATE_TEST_CASE_P(VideoUtilSarTestInstance, + VideoUtilSarTest, + Values(SarTestData{1024, 768, 1024, 768, 1, 1}, + SarTestData{1024, 384, 1024, 768, 1, 2}, + SarTestData{512, 768, 1024, 768, 2, 1}, + SarTestData{1024, 1024, 1024, 768, 4, 3}, + SarTestData{123, 567, 1024, 768, 252, 41})); + +} // namespace media +} // namespace shaka diff --git a/packager/media/formats/mp4/mp4_media_parser.cc b/packager/media/formats/mp4/mp4_media_parser.cc index 5288cb4e0d..5dcf329ce9 100644 --- a/packager/media/formats/mp4/mp4_media_parser.cc +++ b/packager/media/formats/mp4/mp4_media_parser.cc @@ -5,7 +5,6 @@ #include "packager/media/formats/mp4/mp4_media_parser.h" #include -#include #include "packager/base/callback.h" #include "packager/base/callback_helpers.h" @@ -21,6 +20,7 @@ #include "packager/media/base/media_sample.h" #include "packager/media/base/rcheck.h" #include "packager/media/base/video_stream_info.h" +#include "packager/media/base/video_util.h" #include "packager/media/codecs/ac3_audio_util.h" #include "packager/media/codecs/av1_codec_configuration_record.h" #include "packager/media/codecs/avc_decoder_configuration_record.h" @@ -115,56 +115,6 @@ Codec ObjectTypeToCodec(ObjectType object_type) { } } -uint64_t CalculateGCD(uint64_t a, uint64_t b) { - while (b != 0) { - uint64_t temp = a; - a = b; - b = temp % b; - } - return a; -} - -void ReducePixelWidthHeight(uint64_t* pixel_width, uint64_t* pixel_height) { - if (*pixel_width == 0 || *pixel_height == 0) - return; - const uint64_t kMaxUint32 = std::numeric_limits::max(); - while (true) { - uint64_t gcd = CalculateGCD(*pixel_width, *pixel_height); - *pixel_width /= gcd; - *pixel_height /= gcd; - // Both width and height needs to be 32 bit or less. - if (*pixel_width <= kMaxUint32 && *pixel_height <= kMaxUint32) - break; - *pixel_width >>= 1; - *pixel_height >>= 1; - } -} - -// Derive pixel aspect ratio from Display Aspect Ratio and Frame Aspect Ratio. -// DAR = PAR * FAR => PAR = DAR / FAR. -// Thus: -// pixel_width display_width frame_width -// ----------- = ------------- / ----------- -// pixel_height display_height frame_height -// So: -// pixel_width display_width x frame_width -// ----------- = ------------------------------ -// pixel_height display_height x frame_height -void DerivePixelWidthHeight(uint32_t frame_width, - uint32_t frame_height, - uint32_t display_width, - uint32_t display_height, - uint32_t* pixel_width, - uint32_t* pixel_height) { - uint64_t pixel_width_unreduced = - static_cast(display_width) * frame_height; - uint64_t pixel_height_unreduced = - static_cast(display_height) * frame_width; - ReducePixelWidthHeight(&pixel_width_unreduced, &pixel_height_unreduced); - *pixel_width = pixel_width_unreduced; - *pixel_height = pixel_height_unreduced; -} - const uint64_t kNanosecondsPerSecond = 1000000000ull; } // namespace diff --git a/packager/media/formats/webm/webm_video_client.cc b/packager/media/formats/webm/webm_video_client.cc index 96335c3d9e..0298a3e486 100644 --- a/packager/media/formats/webm/webm_video_client.cc +++ b/packager/media/formats/webm/webm_video_client.cc @@ -5,6 +5,7 @@ #include "packager/media/formats/webm/webm_video_client.h" #include "packager/base/logging.h" +#include "packager/media/base/video_util.h" #include "packager/media/codecs/av1_codec_configuration_record.h" #include "packager/media/codecs/vp_codec_configuration_record.h" #include "packager/media/formats/webm/webm_constants.h" @@ -14,15 +15,6 @@ namespace { // Timestamps are represented in double in WebM. Convert to uint64_t in us. const uint32_t kWebMTimeScale = 1000000u; -int64_t GetGreatestCommonDivisor(int64_t a, int64_t b) { - while (b) { - int64_t temp = b; - b = a % b; - a = temp; - } - return a; -} - } // namespace namespace shaka { @@ -118,12 +110,12 @@ std::shared_ptr WebMVideoClient::GetVideoStreamInfo( LOG(ERROR) << "Unsupported display unit type " << display_unit_; return nullptr; } + // Calculate sample aspect ratio. - int64_t sar_x = display_width_ * height_after_crop; - int64_t sar_y = display_height_ * width_after_crop; - int64_t gcd = GetGreatestCommonDivisor(sar_x, sar_y); - sar_x /= gcd; - sar_y /= gcd; + uint32_t pixel_width; + uint32_t pixel_height; + DerivePixelWidthHeight(width_after_crop, height_after_crop, display_width_, + display_height_, &pixel_width, &pixel_height); // |codec_private| may be overriden later for some codecs, e.g. VP9 since for // VP9, the format for MP4 and WebM are different; MP4 format is used as the @@ -131,8 +123,8 @@ std::shared_ptr WebMVideoClient::GetVideoStreamInfo( return std::make_shared( track_num, kWebMTimeScale, 0, video_codec, H26xStreamFormat::kUnSpecified, codec_string, codec_private.data(), codec_private.size(), - width_after_crop, height_after_crop, sar_x, sar_y, 0, 0, std::string(), - is_encrypted); + width_after_crop, height_after_crop, pixel_width, pixel_height, 0, 0, + std::string(), is_encrypted); } VPCodecConfigurationRecord WebMVideoClient::GetVpCodecConfig(