| // 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 "media/muxers/mp4_movie_box_writer.h" |
| |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "base/big_endian.h" |
| #include "media/muxers/box_byte_stream.h" |
| #include "media/muxers/mp4_muxer_context.h" |
| #include "media/muxers/output_position_tracker.h" |
| |
| namespace media { |
| |
| namespace {} // namespace |
| |
| Mp4MovieBoxWriter::Mp4MovieBoxWriter(const Mp4MuxerContext& context, |
| const mp4::writable_boxes::Movie& box) |
| : Mp4BoxWriter(context), movie_box_(box) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| AddChildBox( |
| std::make_unique<Mp4MovieHeaderBoxWriter>(context, movie_box_.header)); |
| } |
| |
| Mp4MovieBoxWriter::~Mp4MovieBoxWriter() = default; |
| |
| void Mp4MovieBoxWriter::Write(BoxByteStream& writer) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| WriteBox(writer, movie_box_.fourcc); |
| |
| // Write the children. |
| WriteChildren(writer); |
| } |
| |
| Mp4MovieHeaderBoxWriter::Mp4MovieHeaderBoxWriter( |
| const Mp4MuxerContext& context, |
| const mp4::writable_boxes::MovieHeader& box) |
| : Mp4BoxWriter(context), movie_header_box_(box) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| } |
| |
| Mp4MovieHeaderBoxWriter::~Mp4MovieHeaderBoxWriter() = default; |
| |
| void Mp4MovieHeaderBoxWriter::Write(BoxByteStream& writer) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| WriteFullBox(writer, movie_header_box_.fourcc); |
| |
| // Convert to ISO time, seconds since midnight, Jan. 1, 1904, in UTC time. |
| // base::Time time1904; |
| // base::Time::FromUTCString("1904-01-01 00:00:00 UTC", &time1904); |
| // 9561628800 = time1904.ToDeltaSinceWindowsEpoch().InSeconds(); |
| constexpr int64_t k1601To1904DeltaInSeconds = INT64_C(9561628800); |
| |
| uint64_t iso_creation_time = |
| movie_header_box_.creation_time.ToDeltaSinceWindowsEpoch().InSeconds() - |
| k1601To1904DeltaInSeconds; |
| uint64_t iso_modification_time = |
| movie_header_box_.modification_time.ToDeltaSinceWindowsEpoch() |
| .InSeconds() - |
| k1601To1904DeltaInSeconds; |
| |
| writer.WriteU64(iso_creation_time); |
| writer.WriteU64(iso_modification_time); |
| writer.WriteU32(movie_header_box_.timescale); |
| writer.WriteU64(movie_header_box_.duration.InSeconds()); |
| |
| writer.WriteU32(0x00010000); // normal rate. |
| writer.WriteU16(0x0100); // full volume. |
| writer.WriteU16(0); // reserved. |
| writer.WriteU32(0); // reserved. |
| writer.WriteU32(0); // reserved. |
| |
| // ISO/IEC 14496-12. |
| // A transformation matrix for the video. |
| // Video frames are not scaled, rotated, or skewed, and are displayed at |
| // their original size with no zoom or depth applied. |
| |
| // The value 0x00010000 in the top-left and middle element of the |
| // matrix specifies the horizontal and vertical scaling factor, |
| // respectively. This means that the video frames are not scaled and |
| // are displayed at their original size. |
| |
| // The bottom-right element of the matrix, with a value of 0x40000000, |
| // specifies the fixed-point value of the zoom or depth of the video frames. |
| // This value is equal to 1.0 in decimal notation, meaning that there |
| // is no zoom or depth applied to the video frames. |
| constexpr int32_t kDisplayIdentityMatrix[9] = { |
| 0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000}; |
| |
| for (auto* it = std::begin(kDisplayIdentityMatrix); |
| it != std::end(kDisplayIdentityMatrix); ++it) { |
| writer.WriteU32(*it); |
| } |
| |
| // uint32_t type of predefined[6]. |
| for (uint32_t i = 0; i < 6; ++i) { |
| writer.WriteU32(0); |
| } |
| |
| writer.WriteU32(movie_header_box_.next_track_id); |
| |
| // Write the children. |
| WriteChildren(writer); |
| } |
| |
| } // namespace media |