Commit c4328744 authored by Dale Curtis's avatar Dale Curtis Committed by Commit Bot

Add ID3v2 metadata parsing for Shaka packager detection.

This will help understand how frequently Shaka packager is used in
the wild. If usage is high enough we may add a UKM to figure out
whom it's most popular with.

BUG=927952

Change-Id: I144fa524fd2450e5fdd31f9baa24a9bc7b6bfbee
Reviewed-on: https://chromium-review.googlesource.com/c/1464921
Commit-Queue: Mark Pearson <mpearson@chromium.org>
Reviewed-by: default avatarMark Pearson <mpearson@chromium.org>
Reviewed-by: default avatarMatthew Wolenetz <wolenetz@chromium.org>
Auto-Submit: Dale Curtis <dalecurtis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#636273}
parent a75e9c43
...@@ -4,14 +4,17 @@ ...@@ -4,14 +4,17 @@
#include "media/formats/mp4/box_definitions.h" #include "media/formats/mp4/box_definitions.h"
#include <algorithm>
#include <memory> #include <memory>
#include <utility> #include <utility>
#include "base/command_line.h" #include "base/command_line.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/numerics/safe_math.h" #include "base/numerics/safe_math.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "media/base/media_switches.h" #include "media/base/media_switches.h"
#include "media/base/media_util.h" #include "media/base/media_util.h"
...@@ -1379,6 +1382,11 @@ bool Movie::Parse(BoxReader* reader) { ...@@ -1379,6 +1382,11 @@ bool Movie::Parse(BoxReader* reader) {
"require ISO BMFF moov to contain mvex to indicate that " "require ISO BMFF moov to contain mvex to indicate that "
"Movie Fragments are to be expected."); "Movie Fragments are to be expected.");
MetadataBox meta;
RCHECK(reader->MaybeReadChild(&meta));
base::UmaHistogramBoolean("Media.MSE.DetectedShakaPackagerInMp4",
meta.used_shaka_packager);
return reader->MaybeReadChildren(&pssh); return reader->MaybeReadChildren(&pssh);
} }
...@@ -1761,5 +1769,48 @@ SampleDependsOn IndependentAndDisposableSamples::sample_depends_on( ...@@ -1761,5 +1769,48 @@ SampleDependsOn IndependentAndDisposableSamples::sample_depends_on(
return sample_depends_on_[i]; return sample_depends_on_[i];
} }
ID3v2Box::ID3v2Box() = default;
ID3v2Box::ID3v2Box(const ID3v2Box& other) = default;
ID3v2Box::~ID3v2Box() = default;
FourCC ID3v2Box::BoxType() const {
return FOURCC_ID32;
}
bool ID3v2Box::Parse(BoxReader* reader) {
// This is reading the ID32 box without regard for what's in it -- there will
// likely be binary data in this vector. We don't care though since we're just
// going to scan the memory without caring about sentinel values like \0.
RCHECK(reader->ReadVec(&id3v2_data,
std::min(static_cast<size_t>(128),
reader->buffer_size() - reader->pos())));
return true;
}
MetadataBox::MetadataBox() : used_shaka_packager(false) {}
MetadataBox::MetadataBox(const MetadataBox& other) = default;
MetadataBox::~MetadataBox() = default;
FourCC MetadataBox::BoxType() const {
return FOURCC_META;
}
bool MetadataBox::Parse(BoxReader* reader) {
RCHECK(reader->ReadFullBoxHeader());
// This is an optional box, so generate no errors.
if (!reader->ScanChildren())
return true;
ID3v2Box id3v2;
if (!reader->ReadChild(&id3v2))
return true;
constexpr char kShakaPackager[] = "shaka-packager";
used_shaka_packager =
base::StringPiece(reinterpret_cast<char*>(id3v2.id3v2_data.data()),
id3v2.id3v2_data.size())
.find(kShakaPackager) != base::StringPiece::npos;
return true;
}
} // namespace mp4 } // namespace mp4
} // namespace media } // namespace media
...@@ -549,6 +549,18 @@ struct MEDIA_EXPORT MovieFragment : Box { ...@@ -549,6 +549,18 @@ struct MEDIA_EXPORT MovieFragment : Box {
std::vector<ProtectionSystemSpecificHeader> pssh; std::vector<ProtectionSystemSpecificHeader> pssh;
}; };
struct MEDIA_EXPORT ID3v2Box : Box {
DECLARE_BOX_METHODS(ID3v2Box);
// Up to a maximum of the first 128 bytes of the ID3v2 box.
std::vector<uint8_t> id3v2_data;
};
struct MEDIA_EXPORT MetadataBox : Box {
DECLARE_BOX_METHODS(MetadataBox);
bool used_shaka_packager;
};
#undef DECLARE_BOX #undef DECLARE_BOX
} // namespace mp4 } // namespace mp4
......
...@@ -60,6 +60,7 @@ enum FourCC { ...@@ -60,6 +60,7 @@ enum FourCC {
FOURCC_HVC1 = 0x68766331, FOURCC_HVC1 = 0x68766331,
FOURCC_HVCC = 0x68766343, FOURCC_HVCC = 0x68766343,
#endif #endif
FOURCC_ID32 = 0x49443332,
FOURCC_IODS = 0x696f6473, FOURCC_IODS = 0x696f6473,
FOURCC_MDAT = 0x6d646174, FOURCC_MDAT = 0x6d646174,
FOURCC_MDHD = 0x6d646864, FOURCC_MDHD = 0x6d646864,
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "base/bind_helpers.h" #include "base/bind_helpers.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "media/base/audio_decoder_config.h" #include "media/base/audio_decoder_config.h"
...@@ -258,6 +259,35 @@ TEST_F(MP4StreamParserTest, UnalignedAppend) { ...@@ -258,6 +259,35 @@ TEST_F(MP4StreamParserTest, UnalignedAppend) {
ParseMP4File("bear-1280x720-av_frag.mp4", 512); ParseMP4File("bear-1280x720-av_frag.mp4", 512);
} }
constexpr char kShakaPackagerUMA[] = "Media.MSE.DetectedShakaPackagerInMp4";
TEST_F(MP4StreamParserTest, DidNotUseShakaPackager) {
// Encrypted files have non-zero duration and are treated as recorded streams.
auto params = GetDefaultInitParametersExpectations();
params.duration = base::TimeDelta::FromMicroseconds(2736066);
params.liveness = DemuxerStream::LIVENESS_RECORDED;
params.detected_audio_track_count = 0;
InitializeParserWithInitParametersExpectations(params);
base::HistogramTester tester;
// Test file has ID32 box, but no shaka player metadata.
ParseMP4File("bear-640x360-v_frag-cenc-senc-no-saiz-saio.mp4", 512);
tester.ExpectUniqueSample(kShakaPackagerUMA, 0, 1);
}
TEST_F(MP4StreamParserTest, UsedShakaPackager) {
auto params = GetDefaultInitParametersExpectations();
params.duration = base::TimeDelta::FromMicroseconds(2736000);
params.liveness = DemuxerStream::LIVENESS_RECORDED;
params.detected_audio_track_count = 0;
InitializeParserWithInitParametersExpectations(params);
base::HistogramTester tester;
ParseMP4File("bear-320x240-v_frag-vp9.mp4", 512);
tester.ExpectUniqueSample(kShakaPackagerUMA, 1, 1);
}
TEST_F(MP4StreamParserTest, BytewiseAppend) { TEST_F(MP4StreamParserTest, BytewiseAppend) {
// Ensure no incremental errors occur when parsing // Ensure no incremental errors occur when parsing
InitializeParser(); InitializeParser();
......
...@@ -49646,6 +49646,17 @@ uploading your change for review. ...@@ -49646,6 +49646,17 @@ uploading your change for review.
</summary> </summary>
</histogram> </histogram>
<histogram name="Media.MSE.DetectedShakaPackagerInMp4" enum="BooleanDetected"
expires_after="2019-12-01">
<owner>dalecurtis@chromium.org</owner>
<owner>media-dev@chromium.org</owner>
<summary>
Tracks if ShakaPackager metadata was detected in the MP4 'moov' atom during
MSE based media playback. Recorded for every 'moov' atom, which is expected
once per asset. Multiple assets may be played within the same MSE session.
</summary>
</histogram>
<histogram name="Media.MSE.DetectedTrackCount.Audio"> <histogram name="Media.MSE.DetectedTrackCount.Audio">
<owner>wolenetz@chromium.org</owner> <owner>wolenetz@chromium.org</owner>
<summary> <summary>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment