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