Shaka Packager SDK
Loading...
Searching...
No Matches
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
15namespace shaka {
16namespace 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
26PackedAudioWriter::~PackedAudioWriter() = default;
27
28Status 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
52Status 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
63Status PackedAudioWriter::AddMediaSample(size_t stream_id,
64 const MediaSample& sample) {
65 DCHECK_EQ(stream_id, 0u);
66 return segmenter_->AddSample(sample);
67}
68
69Status 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
101Status 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
128Status 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.
This structure contains the list of configuration options for Muxer.