Skip to content

Commit

Permalink
LibVideo: Allow the VP9 decoder to decode ultra high resolution video
Browse files Browse the repository at this point in the history
Previously, some integer overflows and truncations were causing parsing
errors for 4K videos, with those fixed it can fully decode 8K video.

This adds a test to ensure that 4K video will continue to be decoded.

Note: There seems to be unexpectedly high memory usage while decoding
them, causing 8K video to require more than a gigabyte of RAM. (!!!)
  • Loading branch information
Zaggy1024 authored and ADKaster committed Oct 12, 2022
1 parent f894e8b commit 41cb705
Show file tree
Hide file tree
Showing 6 changed files with 20 additions and 8 deletions.
1 change: 1 addition & 0 deletions Tests/LibVideo/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ foreach(source IN LISTS TEST_SOURCES)
endforeach()

install(FILES vp9_in_webm.webm DESTINATION usr/Tests/LibVideo)
install(FILES vp9_4k.webm DESTINATION usr/Tests/LibVideo)
17 changes: 14 additions & 3 deletions Tests/LibVideo/TestVP9Decode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@
#include <LibVideo/MatroskaReader.h>
#include <LibVideo/VP9/Decoder.h>

TEST_CASE(webm_in_vp9)
static void decode_video(StringView path, size_t expected_frame_count)
{
auto matroska_document = Video::MatroskaReader::MatroskaReader::parse_matroska_from_file("./vp9_in_webm.webm"sv);
auto matroska_document = Video::MatroskaReader::MatroskaReader::parse_matroska_from_file(path);
VERIFY(matroska_document);
auto video_track_optional = matroska_document->track_for_track_type(Video::TrackEntry::TrackType::Video);
VERIFY(video_track_optional.has_value());
auto video_track_entry = video_track_optional.value();

size_t frame_count = 0;
size_t cluster_index, block_index, frame_index;
Video::VP9::Decoder vp9_decoder;

Expand All @@ -29,9 +30,19 @@ TEST_CASE(webm_in_vp9)

for (frame_index = 0; frame_index < block.frames().size(); frame_index++) {
MUST(vp9_decoder.decode(block.frames()[frame_index]));
frame_count++;
}
}
}
VERIFY(frame_count == expected_frame_count);
}

VERIFY(cluster_index == 1 && block_index == 25 && frame_index == 1);
TEST_CASE(webm_in_vp9)
{
decode_video("./vp9_in_webm.webm"sv, 25);
}

BENCHMARK_CASE(vp9_4k)
{
decode_video("./vp9_4k.webm"sv, 2);
}
Binary file added Tests/LibVideo/vp9_4k.webm
Binary file not shown.
2 changes: 1 addition & 1 deletion Userland/Libraries/LibVideo/VP9/Decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1097,7 +1097,7 @@ inline i32 Decoder::round_2(T value, u8 bits)

inline bool check_bounds(i64 value, u8 bits)
{
const i64 maximum = (1u << (bits - 1u)) - 1u;
i64 const maximum = (1ll << (bits - 1ll)) - 1ll;
return value >= ~maximum && value <= maximum;
}

Expand Down
6 changes: 3 additions & 3 deletions Userland/Libraries/LibVideo/VP9/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -979,8 +979,8 @@ DecoderErrorOr<void> Parser::decode_block(u32 row, u32 col, BlockSubsize subsize
// write out of bounds. This check seems consistent with libvpx.
// See here:
// https://github.com/webmproject/libvpx/blob/705bf9de8c96cfe5301451f1d7e5c90a41c64e5f/vp9/decoder/vp9_decodeframe.c#L917
auto maximum_block_y = min(num_8x8_blocks_high_lookup[subsize], m_mi_rows - row);
auto maximum_block_x = min(num_8x8_blocks_wide_lookup[subsize], m_mi_cols - col);
auto maximum_block_y = min<u32>(num_8x8_blocks_high_lookup[subsize], m_mi_rows - row);
auto maximum_block_x = min<u32>(num_8x8_blocks_wide_lookup[subsize], m_mi_cols - col);

for (size_t y = 0; y < maximum_block_y; y++) {
for (size_t x = 0; x < maximum_block_x; x++) {
Expand Down Expand Up @@ -1337,7 +1337,7 @@ DecoderErrorOr<i32> Parser::read_mv_component(u8 component)
return (mv_sign ? -1 : 1) * static_cast<i32>(mag);
}

Gfx::Point<size_t> Parser::get_decoded_point_for_plane(u8 column, u8 row, u8 plane)
Gfx::Point<size_t> Parser::get_decoded_point_for_plane(u32 column, u32 row, u8 plane)
{
if (plane == 0)
return { column * 8, row * 8 };
Expand Down
2 changes: 1 addition & 1 deletion Userland/Libraries/LibVideo/VP9/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ class Parser {
void scale_mv(u8 ref_list, ReferenceFrame ref_frame);
void add_mv_ref_list(u8 ref_list);

Gfx::Point<size_t> get_decoded_point_for_plane(u8 row, u8 column, u8 plane);
Gfx::Point<size_t> get_decoded_point_for_plane(u32 row, u32 column, u8 plane);
Gfx::Size<size_t> get_decoded_size_for_plane(u8 plane);

u8 m_profile { 0 };
Expand Down

0 comments on commit 41cb705

Please sign in to comment.