• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023, Alliance for Open Media. All rights reserved
3  *
4  * This source code is subject to the terms of the BSD 3-Clause Clear License
5  * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
6  * License was not distributed with this source code in the LICENSE file, you
7  * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
8  * Alliance for Open Media Patent License 1.0 was not distributed with this
9  * source code in the PATENTS file, you can obtain it at
10  * www.aomedia.org/license/patent.
11  */
12 #include "iamf/cli/obu_sequencer_iamf.h"
13 
14 #include <cstdint>
15 #include <filesystem>
16 #include <fstream>
17 #include <ios>
18 #include <optional>
19 #include <string>
20 #include <system_error>
21 
22 #include "absl/log/check.h"
23 #include "absl/log/log.h"
24 #include "absl/status/status.h"
25 #include "absl/types/span.h"
26 #include "iamf/cli/obu_sequencer_base.h"
27 #include "iamf/common/leb_generator.h"
28 #include "iamf/common/utils/macros.h"
29 #include "iamf/common/write_bit_buffer.h"
30 
31 namespace iamf_tools {
32 
33 namespace {
34 
35 constexpr int64_t kBufferStartSize = 65536;
36 
37 // This sequencer does not care about the delay or timing information. It would
38 // be pointless to delay the descriptor OBUs.
39 constexpr bool kDoNotDelayDescriptorsUntilFirstUntrimmedSample = false;
40 
MaybeRemoveFile(const std::string & filename,std::optional<std::fstream> & file_to_remove)41 void MaybeRemoveFile(const std::string& filename,
42                      std::optional<std::fstream>& file_to_remove) {
43   if (filename.empty() || !file_to_remove.has_value()) {
44     return;
45   }
46 
47   // Close and delete the file.
48   file_to_remove->close();
49   file_to_remove = std::nullopt;
50   std::error_code error_code;
51   std::filesystem::remove(filename, error_code);
52   if (!error_code) {
53     // File clean up failed somehow. Just log the error and move on.
54     LOG(ERROR).WithPerror() << "Failed to remove " << filename;
55   }
56 }
57 
58 }  // namespace
59 
ObuSequencerIamf(const std::string & iamf_filename,bool include_temporal_delimiters,const LebGenerator & leb_generator)60 ObuSequencerIamf::ObuSequencerIamf(const std::string& iamf_filename,
61                                    bool include_temporal_delimiters,
62                                    const LebGenerator& leb_generator)
63     : ObuSequencerBase(leb_generator, include_temporal_delimiters,
64                        kDoNotDelayDescriptorsUntilFirstUntrimmedSample),
65       iamf_filename_(iamf_filename),
66       wb_(kBufferStartSize, leb_generator) {}
67 
PushSerializedDescriptorObus(uint32_t,uint32_t,uint8_t,std::optional<int64_t>,int,absl::Span<const uint8_t> descriptor_obus)68 absl::Status ObuSequencerIamf::PushSerializedDescriptorObus(
69     uint32_t /*common_samples_per_frame*/, uint32_t /*common_sample_rate*/,
70     uint8_t /*common_bit_depth*/,
71     std::optional<int64_t> /*first_untrimmed_timestamp*/, int /*num_channels*/,
72     absl::Span<const uint8_t> descriptor_obus) {
73   if (!iamf_filename_.empty()) {
74     LOG(INFO) << "Writing descriptor OBUs to " << iamf_filename_;
75 
76     output_iamf_.emplace(iamf_filename_, std::fstream::out | std::ios::binary);
77   }
78 
79   RETURN_IF_NOT_OK(wb_.WriteUint8Span(descriptor_obus));
80   return wb_.FlushAndWriteToFile(output_iamf_);
81 }
82 
PushSerializedTemporalUnit(int64_t,int,absl::Span<const uint8_t> temporal_unit)83 absl::Status ObuSequencerIamf::PushSerializedTemporalUnit(
84     int64_t /*timestamp*/, int /*num_samples*/,
85     absl::Span<const uint8_t> temporal_unit) {
86   RETURN_IF_NOT_OK(wb_.WriteUint8Span(temporal_unit));
87   return wb_.FlushAndWriteToFile(output_iamf_);
88 }
89 
PushFinalizedDescriptorObus(absl::Span<const uint8_t> descriptor_obus)90 absl::Status ObuSequencerIamf::PushFinalizedDescriptorObus(
91     absl::Span<const uint8_t> descriptor_obus) {
92   if (output_iamf_.has_value()) {
93     // For good practice, restore the previous position in the file after we
94     // rewrite. But in reality this function usually will be called right before
95     // closing the file.
96     const auto previous_position = output_iamf_->tellg();
97     output_iamf_->seekg(0, std::ios::beg);
98     RETURN_IF_NOT_OK(wb_.WriteUint8Span(descriptor_obus));
99     RETURN_IF_NOT_OK(wb_.FlushAndWriteToFile(output_iamf_));
100 
101     output_iamf_->seekg(previous_position);
102   }
103 
104   return absl::OkStatus();
105 }
106 
CloseDerived()107 void ObuSequencerIamf::CloseDerived() {
108   if (output_iamf_.has_value() && output_iamf_->is_open()) {
109     output_iamf_->close();
110     output_iamf_ = std::nullopt;
111   }
112 }
113 
AbortDerived()114 void ObuSequencerIamf::AbortDerived() {
115   LOG(INFO) << "Aborting ObuSequencerIamf.";
116   MaybeRemoveFile(iamf_filename_, output_iamf_);
117 }
118 
119 }  // namespace iamf_tools
120