From e3c95767162f81fc69318d0837683d14377a35f3 Mon Sep 17 00:00:00 2001 From: Frank Galligan Date: Tue, 26 Apr 2016 09:51:59 -0700 Subject: [PATCH] Add VP9 level output to webm_info. Removed building webm_info from Makefile.unix as it now requires c++11. BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1188 Change-Id: Ia142f0c3cd580f397449d2ffa8788f78fb7faff0 --- CMakeLists.txt | 9 +++++- Makefile.unix | 9 ++---- build/cxx11_tests.cmake | 1 + common/vp9_header_parser.h | 3 ++ webm_info.cc | 60 ++++++++++++++++++++++++++++---------- 5 files changed, 58 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f31e0ed..6b9beda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ set(LIBWEBM_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}") # Build/test configuration flags. Defined here for visibility. option(ENABLE_WEBMTS "Enables WebM PES/TS support." ON) +option(ENABLE_WEBMINFO "Enables building webm_info." ON) option(ENABLE_TESTS "Enables tests." OFF) option(ENABLE_IWYU "Enables include-what-you-use support." OFF) option(ENABLE_WERROR "Enable warnings as errors." OFF) @@ -24,7 +25,7 @@ set(GTEST_SRC_DIR "${LIBWEBM_SRC_DIR}/../googletest" CACHE PATH set(GTEST_BUILD_DIR "${CMAKE_BINARY_DIR}/googletest_build") include("${CMAKE_CURRENT_SOURCE_DIR}/build/cxx_flags.cmake") -if (ENABLE_TESTS OR ENABLE_WEBMTS) +if (ENABLE_TESTS OR ENABLE_WEBMTS OR ENABLE_WEBMINFO) include("${CMAKE_CURRENT_SOURCE_DIR}/build/cxx11_tests.cmake") endif () @@ -103,15 +104,21 @@ add_executable(vttdemux "${LIBWEBM_SRC_DIR}/webvtt/webvttparser.h") target_link_libraries(vttdemux LINK_PUBLIC webm) +if (ENABLE_WEBMINFO) # Webm_info section. add_executable(webm_info "${LIBWEBM_SRC_DIR}/common/indent.cc" "${LIBWEBM_SRC_DIR}/common/indent.h" + "${LIBWEBM_SRC_DIR}/common/vp9_header_parser.cc" + "${LIBWEBM_SRC_DIR}/common/vp9_header_parser.h" + "${LIBWEBM_SRC_DIR}/common/vp9_level_stats.cc" + "${LIBWEBM_SRC_DIR}/common/vp9_level_stats.h" "${LIBWEBM_SRC_DIR}/common/webm_constants.h" "${LIBWEBM_SRC_DIR}/common/webm_endian.cc" "${LIBWEBM_SRC_DIR}/common/webm_endian.h" "${LIBWEBM_SRC_DIR}/webm_info.cc") target_link_libraries(webm_info LINK_PUBLIC webm) +endif () if (ENABLE_WEBMTS) # webmts (PES/TS support) library section. diff --git a/Makefile.unix b/Makefile.unix index 7a852ba..ab666ff 100644 --- a/Makefile.unix +++ b/Makefile.unix @@ -12,12 +12,10 @@ WEBMOBJS += common/file_util.o common/hdr_util.o OBJSA := $(WEBMOBJS:.o=_a.o) OBJSSO := $(WEBMOBJS:.o=_so.o) VTTOBJS := webvtt/vttreader.o webvtt/webvttparser.o sample_muxer_metadata.o -EXEOBJS := sample.o sample_muxer.o dumpvtt.o vttdemux.o webm_info.o -INFOOBJS := common/indent.o common/webm_endian.o +EXEOBJS := sample.o sample_muxer.o dumpvtt.o vttdemux.o DEPS := $(WEBMOBJS:.o=.d) $(OBJECTS1:.o=.d) $(OBJECTS2:.o=.d) DEPS += $(OBJECTS3:.o=.d) $(OBJECTS4:.o=.d) $(OBJSA:.o=.d) $(OBJSSO:.o=.d) -DEPS += $(VTTOBJS:.o=.d) $(EXEOBJS:.o=.d) $(INFOOBJS:.o=.d) -EXES := sample_muxer sample dumpvtt vttdemux webm_info +DEPS += $(VTTOBJS:.o=.d) $(EXEOBJS:.o=.d) CLEAN := $(EXEOBJS) $(VTTOBJS) $(WEBMOBJS) $(OBJSA) $(OBJSSO) $(LIBWEBMA) CLEAN += $(LIBWEBMSO) $(EXES) $(DEPS) $(INFOOBJS) @@ -35,9 +33,6 @@ dumpvtt: dumpvtt.o $(VTTOBJS) $(WEBMOBJS) vttdemux: vttdemux.o $(VTTOBJS) $(LIBWEBMA) $(CXX) $^ -o $@ -webm_info: webm_info.o $(INFOOBJS) $(LIBWEBMA) - $(CXX) $^ -o $@ - shared: $(LIBWEBMSO) libwebm.a: $(OBJSA) diff --git a/build/cxx11_tests.cmake b/build/cxx11_tests.cmake index 3b5145c..6203acc 100644 --- a/build/cxx11_tests.cmake +++ b/build/cxx11_tests.cmake @@ -135,5 +135,6 @@ if (NOT HAVE_UNIQUE_PTR # TODO(tomfinegan): Update settings at the include site instead of in here. set(ENABLE_TESTS OFF) set(ENABLE_WEBMTS OFF) + set(ENABLE_WEBMINFO OFF) message(WARNING "C++11 feature(s) not supported, tests and webmts disabled.") endif () diff --git a/common/vp9_header_parser.h b/common/vp9_header_parser.h index 7f2d714..ea975b8 100644 --- a/common/vp9_header_parser.h +++ b/common/vp9_header_parser.h @@ -59,9 +59,12 @@ class Vp9HeaderParser { bool ParseUncompressedHeader(); size_t frame_size() const { return frame_size_; } + int profile() const { return profile_; } int key() const { return key_; } int altref() const { return altref_; } + int error_resilient_mode() const { return error_resilient_mode_; } int bit_depth() const { return bit_depth_; } + int color_space() const { return color_space_; } int width() const { return width_; } int height() const { return height_; } int refresh_frame_flags() const { return refresh_frame_flags_; } diff --git a/webm_info.cc b/webm_info.cc index 0135cfb..ddeb83e 100644 --- a/webm_info.cc +++ b/webm_info.cc @@ -18,6 +18,8 @@ #include "common/hdr_util.h" #include "common/indent.h" +#include "common/vp9_header_parser.h" +#include "common/vp9_level_stats.h" #include "common/webm_constants.h" #include "common/webm_endian.h" @@ -33,7 +35,7 @@ using libwebm::Indent; using libwebm::kNanosecondsPerSecond; using libwebm::kNanosecondsPerSecondi; -const char VERSION_STRING[] = "1.0.3.1"; +const char VERSION_STRING[] = "1.0.4.0"; struct Options { Options(); @@ -61,6 +63,7 @@ struct Options { bool output_encrypted_info; bool output_cues; bool output_frame_stats; + bool output_vp9_level; }; Options::Options() @@ -80,7 +83,8 @@ Options::Options() output_clusters_size(false), output_encrypted_info(false), output_cues(false), - output_frame_stats(false) {} + output_frame_stats(false), + output_vp9_level(false) {} void Options::SetAll(bool value) { output_video = value; @@ -99,6 +103,7 @@ void Options::SetAll(bool value) { output_encrypted_info = value; output_cues = value; output_frame_stats = value; + output_vp9_level = value; } bool Options::MatchesBooleanOption(const string& option, const string& value) { @@ -155,6 +160,7 @@ void Usage() { printf(" -encrypted_info Output encrypted frame info (false)\n"); printf(" -cues Output Cues entries (false)\n"); printf(" -frame_stats Output frame stats (VP9)(false)\n"); + printf(" -vp9_level Output VP9 level(false)\n"); printf("\nOutput options may be negated by prefixing 'no'.\n"); } @@ -654,7 +660,8 @@ void ParseSuperframeIndex(const uint8_t* data, size_t data_sz, } void PrintVP9Info(const uint8_t* data, int size, FILE* o, int64_t time_ns, - FrameStats* stats) { + FrameStats* stats, vp9_parser::Vp9HeaderParser* parser, + vp9_parser::Vp9LevelStats* level_stats) { if (size < 1) return; @@ -668,16 +675,16 @@ void PrintVP9Info(const uint8_t* data, int size, FILE* o, int64_t time_ns, stats->window.pop(); do { + const size_t frame_length = (count > 0) ? sizes[i] : size; + parser->SetFrame(data, frame_length); + parser->ParseUncompressedHeader(); + level_stats->AddFrame(*parser, time_ns); + // const int frame_marker = (data[0] >> 6) & 0x3; - // TODO(jzern): profile > 2 uses 3 bits in the header. - const int version = (data[0] >> 4) & 0x3; - const int key = !((data[0] >> 2) & 0x1); - const int altref_frame = !((data[0] >> 1) & 0x1); - const int error_resilient_mode = data[0] & 0x1; - if (version > 2) { - fprintf(o, " profile > 2 is unsupported"); - return; - } + const int version = parser->profile(); + const int key = parser->key(); + const int altref_frame = parser->altref(); + const int error_resilient_mode = parser->error_resilient_mode(); if (key && !(size >= 4 && data[1] == 0x49 && data[2] == 0x83 && data[3] == 0x42)) { @@ -710,7 +717,7 @@ void PrintVP9Info(const uint8_t* data, int size, FILE* o, int64_t time_ns, error_resilient_mode); if (key && size > 4) { - fprintf(o, " cs:%d", (data[4] >> 5) & 0x7); + fprintf(o, " cs:%d", parser->color_space()); } if (count > 0) { @@ -748,7 +755,9 @@ void PrintVP8Info(const uint8_t* data, int size, FILE* o) { bool OutputCluster(const mkvparser::Cluster& cluster, const mkvparser::Tracks& tracks, const Options& options, FILE* o, mkvparser::MkvReader* reader, Indent* indent, - int64_t* clusters_size, FrameStats* stats) { + int64_t* clusters_size, FrameStats* stats, + vp9_parser::Vp9HeaderParser* parser, + vp9_parser::Vp9LevelStats* level_stats) { if (clusters_size) { // Load the Cluster. const mkvparser::BlockEntry* block_entry; @@ -925,7 +934,7 @@ bool OutputCluster(const mkvparser::Cluster& cluster, PrintVP8Info(data, static_cast(frame.len), o); } else if (codec_id == "V_VP9") { PrintVP9Info(data, static_cast(frame.len), o, time_ns, - stats); + stats, parser, level_stats); } } } @@ -1081,6 +1090,8 @@ int main(int argc, char* argv[]) { options.output_cues = !strcmp("-cues", argv[i]); } else if (Options::MatchesBooleanOption("frame_stats", argv[i])) { options.output_frame_stats = !strcmp("-frame_stats", argv[i]); + } else if (Options::MatchesBooleanOption("vp9_level", argv[i])) { + options.output_vp9_level = !strcmp("-vp9_level", argv[i]); } } @@ -1166,10 +1177,12 @@ int main(int argc, char* argv[]) { int64_t clusters_size = 0; FrameStats stats; + vp9_parser::Vp9HeaderParser parser; + vp9_parser::Vp9LevelStats level_stats; const mkvparser::Cluster* cluster = segment->GetFirst(); while (cluster != NULL && !cluster->EOS()) { if (!OutputCluster(*cluster, *tracks, options, out, reader.get(), &indent, - &clusters_size, &stats)) + &clusters_size, &stats, &parser, &level_stats)) return EXIT_FAILURE; cluster = segment->GetNext(cluster); } @@ -1205,5 +1218,20 @@ int main(int argc, char* argv[]) { fprintf(out, "Maximum Window:%g-%g seconds Window fps:%" PRId64 "\n", sec_start, sec_end, stats.max_window_size); } + + if (options.output_vp9_level) { + level_stats.set_duration(segment->GetInfo()->GetDuration()); + const vp9_parser::Vp9Level level = level_stats.GetLevel(); + fprintf(out, "VP9 Level:%d\n", level); + fprintf(out, "mlsr:%" PRId64 " mlps:%" PRId64 + " abr:%g mcs:%g cr:%g mct:%d" + " mad:%d mrf:%d\n", + level_stats.GetMaxLumaSampleRate(), + level_stats.GetMaxLumaPictureSize(), + level_stats.GetAverageBitRate(), level_stats.GetMaxCpbSize(), + level_stats.GetCompressionRatio(), level_stats.GetMaxColumnTiles(), + level_stats.GetMinimumAltrefDistance(), + level_stats.GetMaxReferenceFrames()); + } return EXIT_SUCCESS; }