Shaka Packager SDK
packed_audio_writer.cc
1 // Copyright 2018 Google LLC. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include <packager/media/formats/packed_audio/packed_audio_writer.h>
8 
9 #include <absl/log/check.h>
10 
11 #include <packager/macros/status.h>
12 #include <packager/media/base/muxer_util.h>
13 #include <packager/media/formats/packed_audio/packed_audio_segmenter.h>
14 
15 namespace shaka {
16 namespace media {
17 
19  : Muxer(muxer_options),
20  transport_stream_timestamp_offset_(
21  muxer_options.transport_stream_timestamp_offset_ms *
22  kPackedAudioTimescale / 1000),
23  segmenter_(new PackedAudioSegmenter(transport_stream_timestamp_offset_)) {
24 }
25 
26 PackedAudioWriter::~PackedAudioWriter() = default;
27 
28 Status PackedAudioWriter::InitializeMuxer() {
29  if (streams().size() > 1u)
30  return Status(error::MUXER_FAILURE, "Cannot handle more than one streams.");
31 
32  RETURN_IF_ERROR(segmenter_->Initialize(*streams()[0]));
33 
34  if (options().segment_template.empty()) {
35  const std::string& file_name = options().output_file_name;
36  DCHECK(!file_name.empty());
37  output_file_.reset(File::Open(file_name.c_str(), "w"));
38  if (!output_file_) {
39  return Status(error::FILE_FAILURE,
40  "Cannot open file for write " + file_name);
41  }
42  }
43 
44  if (muxer_listener()) {
45  muxer_listener()->OnMediaStart(options(), *streams().front(),
46  kPackedAudioTimescale,
47  MuxerListener::kContainerPackedAudio);
48  }
49  return Status::OK;
50 }
51 
52 Status PackedAudioWriter::Finalize() {
53  if (output_file_)
54  RETURN_IF_ERROR(CloseFile(std::move(output_file_)));
55 
56  if (muxer_listener()) {
57  muxer_listener()->OnMediaEnd(
58  media_ranges_, total_duration_ * segmenter_->TimescaleScale());
59  }
60  return Status::OK;
61 }
62 
63 Status PackedAudioWriter::AddMediaSample(size_t stream_id,
64  const MediaSample& sample) {
65  DCHECK_EQ(stream_id, 0u);
66  return segmenter_->AddSample(sample);
67 }
68 
69 Status PackedAudioWriter::FinalizeSegment(size_t stream_id,
70  const SegmentInfo& segment_info) {
71  DCHECK_EQ(stream_id, 0u);
72  // PackedAudio does not support subsegment.
73  if (segment_info.is_subsegment)
74  return Status::OK;
75 
76  RETURN_IF_ERROR(segmenter_->FinalizeSegment());
77 
78  const int64_t segment_timestamp =
79  segment_info.start_timestamp * segmenter_->TimescaleScale();
80  std::string segment_path =
81  options().segment_template.empty()
82  ? options().output_file_name
83  : GetSegmentName(options().segment_template, segment_timestamp,
84  segment_info.segment_number, options().bandwidth);
85 
86  // Save |segment_size| as it will be cleared after writing.
87  const size_t segment_size = segmenter_->segment_buffer()->Size();
88 
89  RETURN_IF_ERROR(WriteSegment(segment_path, segmenter_->segment_buffer()));
90  total_duration_ += segment_info.duration;
91 
92  if (muxer_listener()) {
93  muxer_listener()->OnNewSegment(
94  segment_path, segment_timestamp + transport_stream_timestamp_offset_,
95  segment_info.duration * segmenter_->TimescaleScale(), segment_size,
96  segment_info.segment_number);
97  }
98  return Status::OK;
99 }
100 
101 Status PackedAudioWriter::WriteSegment(const std::string& segment_path,
102  BufferWriter* segment_buffer) {
103  std::unique_ptr<File, FileCloser> file;
104  if (output_file_) {
105  // This is in single segment mode.
106  Range range;
107  range.start = media_ranges_.subsegment_ranges.empty()
108  ? 0
109  : (media_ranges_.subsegment_ranges.back().end + 1);
110  range.end = range.start + segment_buffer->Size() - 1;
111  media_ranges_.subsegment_ranges.push_back(range);
112  } else {
113  file.reset(File::Open(segment_path.c_str(), "w"));
114  if (!file) {
115  return Status(error::FILE_FAILURE,
116  "Cannot open file for write " + segment_path);
117  }
118  }
119 
120  RETURN_IF_ERROR(segment_buffer->WriteToFile(output_file_ ? output_file_.get()
121  : file.get()));
122 
123  if (file)
124  RETURN_IF_ERROR(CloseFile(std::move(file)));
125  return Status::OK;
126 }
127 
128 Status PackedAudioWriter::CloseFile(std::unique_ptr<File, FileCloser> file) {
129  std::string file_name = file->file_name();
130  if (!file.release()->Close()) {
131  return Status(
132  error::FILE_FAILURE,
133  "Cannot close file " + file_name +
134  ", possibly file permission issue or running out of disk space.");
135  }
136  return Status::OK;
137 }
138 
139 } // namespace media
140 } // namespace shaka
virtual void OnMediaEnd(const MediaRanges &media_ranges, float duration_seconds)=0
virtual void OnMediaStart(const MuxerOptions &muxer_options, const StreamInfo &stream_info, int32_t time_scale, ContainerType container_type)=0
virtual void OnNewSegment(const std::string &segment_name, int64_t start_time, int64_t duration, uint64_t segment_file_size, int64_t segment_number)=0
PackedAudioWriter(const MuxerOptions &muxer_options)
Create a MP4Muxer object from MuxerOptions.
All the methods that are virtual are virtual for mocking.
Definition: crypto_flags.cc:66
This structure contains the list of configuration options for Muxer.
Definition: muxer_options.h:19