blob: bd05dea2cd458691888b1cb191e454f54793dd6e [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include <vector>
#include "base/big_endian.h"
#include "base/containers/span.h"
#include "base/functional/bind.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "media/formats/mp4/box_definitions.h"
#include "media/formats/mp4/box_reader.h"
#include "media/formats/mp4/writable_box_definitions.h"
#include "media/muxers/mp4_box_writer.h"
#include "media/muxers/mp4_movie_box_writer.h"
#include "media/muxers/mp4_muxer_context.h"
#include "media/muxers/output_position_tracker.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
class Mp4MuxerBoxWriterTest : public testing::Test {
public:
Mp4MuxerBoxWriterTest() = default;
protected:
void CreateContext(std::unique_ptr<OutputPositionTracker> tracker) {
context_ = std::make_unique<Mp4MuxerContext>(std::move(tracker));
}
Mp4MuxerContext* context() const { return context_.get(); }
void Reset() { context_ = nullptr; }
private:
mp4::writable_boxes::Movie mp4_moov_box_;
std::unique_ptr<Mp4MuxerContext> context_;
base::test::TaskEnvironment task_environment;
};
TEST_F(Mp4MuxerBoxWriterTest, Mp4MovieAndHeader) {
// Tests `written_data` and `mvhd` box writer.
base::RunLoop run_loop;
std::vector<uint8_t> written_data;
auto tracker = std::make_unique<OutputPositionTracker>(base::BindRepeating(
[&](base::OnceClosure run_loop_quit, std::vector<uint8_t>* written_data,
base::StringPiece mp4_data_string) {
// Callback is called per box output.
std::copy(mp4_data_string.begin(), mp4_data_string.end(),
std::back_inserter(*written_data));
std::move(run_loop_quit).Run();
},
run_loop.QuitClosure(), &written_data));
// Initialize.
CreateContext(std::move(tracker));
context()->SetVideoIndex(0);
// Populates the boxes during Mp4Muxer::OnEncodedVideo.
mp4::writable_boxes::Movie mp4_moov_box;
base::Time creation_time = base::Time::FromTimeT(0x1234567);
base::Time modification_time = base::Time::FromTimeT(0x2345678);
{
mp4_moov_box.fourcc = mp4::FOURCC_MOOV;
mp4_moov_box.header.fourcc = mp4::FOURCC_MVHD;
mp4_moov_box.header.creation_time = creation_time;
mp4_moov_box.header.modification_time = modification_time;
mp4_moov_box.header.timescale = 0x7530;
mp4_moov_box.header.duration = base::Seconds(0);
mp4_moov_box.header.next_track_id = 2;
}
// Flush at requested.
Mp4MovieBoxWriter box_writer(*context(), mp4_moov_box);
box_writer.WriteAndFlush();
// Wait for finishing flush of all boxes.
run_loop.Run();
// Validation of the written boxes.
// `written_data` test.
std::unique_ptr<mp4::BoxReader> reader;
mp4::ParseResult result = mp4::BoxReader::ReadTopLevelBox(
written_data.data(), written_data.size(), nullptr, &reader);
EXPECT_EQ(result, mp4::ParseResult::kOk);
EXPECT_TRUE(reader);
EXPECT_EQ(mp4::FOURCC_MOOV, reader->type());
// `mvhd` test.
std::vector<mp4::MovieHeader> mvhd_boxs;
EXPECT_TRUE(reader->ReadAllChildrenAndCheckFourCC(&mvhd_boxs));
mp4::MovieHeader mvhd_box = mvhd_boxs[0];
EXPECT_EQ(mvhd_box.version, 1);
base::Time time1904;
CHECK(base::Time::FromUTCString("1904-01-01 00:00:00 UTC", &time1904));
uint64_t iso_time_creation_time = (creation_time - time1904).InSeconds();
uint64_t iso_time_modification_time =
(modification_time - time1904).InSeconds();
EXPECT_EQ(mvhd_box.creation_time, iso_time_creation_time);
EXPECT_EQ(mvhd_box.modification_time, iso_time_modification_time);
EXPECT_EQ(mvhd_box.timescale, 0x7530u);
EXPECT_EQ(mvhd_box.duration, 0u);
EXPECT_EQ(mvhd_box.next_track_id, 2u);
// Once Flush, it needs to reset the internal objects of context and buffer.
Reset();
}
} // namespace media