1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cast/standalone_receiver/decoder.h"
6
7 #include <algorithm>
8 #include <sstream>
9 #include <thread>
10
11 #include "util/osp_logging.h"
12 #include "util/trace_logging.h"
13
14 namespace openscreen {
15 namespace cast {
16
Buffer()17 Decoder::Buffer::Buffer() {
18 Resize(0);
19 }
20
21 Decoder::Buffer::~Buffer() = default;
22
Resize(int new_size)23 void Decoder::Buffer::Resize(int new_size) {
24 const int padded_size = new_size + AV_INPUT_BUFFER_PADDING_SIZE;
25 if (static_cast<int>(buffer_.size()) == padded_size) {
26 return;
27 }
28 buffer_.resize(padded_size);
29 // libavcodec requires zero-padding the region at the end, as some decoders
30 // will treat this as a stop marker.
31 memset(buffer_.data() + new_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
32 }
33
GetSpan() const34 absl::Span<const uint8_t> Decoder::Buffer::GetSpan() const {
35 return absl::Span<const uint8_t>(
36 buffer_.data(), buffer_.size() - AV_INPUT_BUFFER_PADDING_SIZE);
37 }
38
GetSpan()39 absl::Span<uint8_t> Decoder::Buffer::GetSpan() {
40 return absl::Span<uint8_t>(buffer_.data(),
41 buffer_.size() - AV_INPUT_BUFFER_PADDING_SIZE);
42 }
43
44 Decoder::Client::Client() = default;
45 Decoder::Client::~Client() = default;
46
Decoder(const std::string & codec_name)47 Decoder::Decoder(const std::string& codec_name) : codec_name_(codec_name) {}
48
49 Decoder::~Decoder() = default;
50
Decode(FrameId frame_id,const Decoder::Buffer & buffer)51 void Decoder::Decode(FrameId frame_id, const Decoder::Buffer& buffer) {
52 TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneReceiver);
53 if (!codec_ && !Initialize()) {
54 return;
55 }
56
57 // Parse the buffer for the required metadata and the packet to send to the
58 // decoder.
59 const absl::Span<const uint8_t> input = buffer.GetSpan();
60 const int bytes_consumed = av_parser_parse2(
61 parser_.get(), context_.get(), &packet_->data, &packet_->size,
62 input.data(), input.size(), AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
63 if (bytes_consumed < 0) {
64 OnError("av_parser_parse2", bytes_consumed, frame_id);
65 return;
66 }
67 if (!packet_->data) {
68 OnError("av_parser_parse2 found no packet", AVERROR_BUFFER_TOO_SMALL,
69 frame_id);
70 return;
71 }
72
73 // Send the packet to the decoder.
74 const int send_packet_result =
75 avcodec_send_packet(context_.get(), packet_.get());
76 if (send_packet_result < 0) {
77 // The result should not be EAGAIN because this code always pulls out all
78 // the decoded frames after feeding-in each AVPacket.
79 OSP_DCHECK_NE(send_packet_result, AVERROR(EAGAIN));
80 OnError("avcodec_send_packet", send_packet_result, frame_id);
81 return;
82 }
83 frames_decoding_.push_back(frame_id);
84
85 // Receive zero or more frames from the decoder.
86 for (;;) {
87 const int receive_frame_result =
88 avcodec_receive_frame(context_.get(), decoded_frame_.get());
89 if (receive_frame_result == AVERROR(EAGAIN)) {
90 break; // Decoder needs more input to produce another frame.
91 }
92 const FrameId decoded_frame_id = DidReceiveFrameFromDecoder();
93 if (receive_frame_result < 0) {
94 OnError("avcodec_receive_frame", receive_frame_result, decoded_frame_id);
95 return;
96 }
97 if (client_) {
98 client_->OnFrameDecoded(decoded_frame_id, *decoded_frame_);
99 }
100 av_frame_unref(decoded_frame_.get());
101 }
102 }
103
Initialize()104 bool Decoder::Initialize() {
105 TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneReceiver);
106 // NOTE: The codec_name values found in OFFER messages, such as "vp8" or
107 // "h264" or "opus" are valid input strings to FFMPEG's look-up function, so
108 // no translation is required here.
109 codec_ = avcodec_find_decoder_by_name(codec_name_.c_str());
110 if (!codec_) {
111 HandleInitializationError("codec not available", AVERROR(EINVAL));
112 return false;
113 }
114 OSP_LOG_INFO << "Found codec: " << codec_name_ << " (known to FFMPEG as "
115 << avcodec_get_name(codec_->id) << ')';
116
117 parser_ = MakeUniqueAVCodecParserContext(codec_->id);
118 if (!parser_) {
119 HandleInitializationError("failed to allocate parser context",
120 AVERROR(ENOMEM));
121 return false;
122 }
123
124 context_ = MakeUniqueAVCodecContext(codec_);
125 if (!context_) {
126 HandleInitializationError("failed to allocate codec context",
127 AVERROR(ENOMEM));
128 return false;
129 }
130
131 // This should always be greater than zero, so that decoding doesn't block the
132 // main thread of this receiver app and cause playback timing issues. The
133 // actual number should be tuned, based on the number of CPU cores.
134 //
135 // This should also be 16 or less, since the encoder implementations emit
136 // warnings about too many encode threads. FFMPEG's VP8 implementation
137 // actually silently freezes if this is 10 or more. Thus, 8 is used for the
138 // max here, just to be safe.
139 context_->thread_count =
140 std::min(std::max<int>(std::thread::hardware_concurrency(), 1), 8);
141 const int open_result = avcodec_open2(context_.get(), codec_, nullptr);
142 if (open_result < 0) {
143 HandleInitializationError("failed to open codec", open_result);
144 return false;
145 }
146
147 packet_ = MakeUniqueAVPacket();
148 if (!packet_) {
149 HandleInitializationError("failed to allocate AVPacket", AVERROR(ENOMEM));
150 return false;
151 }
152
153 decoded_frame_ = MakeUniqueAVFrame();
154 if (!decoded_frame_) {
155 HandleInitializationError("failed to allocate AVFrame", AVERROR(ENOMEM));
156 return false;
157 }
158
159 return true;
160 }
161
DidReceiveFrameFromDecoder()162 FrameId Decoder::DidReceiveFrameFromDecoder() {
163 const auto it = frames_decoding_.begin();
164 OSP_DCHECK(it != frames_decoding_.end());
165 const auto frame_id = *it;
166 frames_decoding_.erase(it);
167 return frame_id;
168 }
169
HandleInitializationError(const char * what,int av_errnum)170 void Decoder::HandleInitializationError(const char* what, int av_errnum) {
171 // If the codec was found, get FFMPEG's canonical name for it.
172 const char* const canonical_name =
173 codec_ ? avcodec_get_name(codec_->id) : nullptr;
174
175 codec_ = nullptr; // Set null to mean "not initialized."
176
177 if (!client_) {
178 return; // Nowhere to emit error to, so don't bother.
179 }
180
181 std::ostringstream error;
182 error << "Could not initialize codec " << codec_name_;
183 if (canonical_name) {
184 error << " (known to FFMPEG as " << canonical_name << ')';
185 }
186 error << " because " << what << " (" << av_err2str(av_errnum) << ").";
187 client_->OnFatalError(error.str());
188 }
189
OnError(const char * what,int av_errnum,FrameId frame_id)190 void Decoder::OnError(const char* what, int av_errnum, FrameId frame_id) {
191 if (!client_) {
192 return;
193 }
194
195 // Make a human-readable string from the libavcodec error.
196 std::ostringstream error;
197 if (!frame_id.is_null()) {
198 error << "frame: " << frame_id << "; ";
199 }
200
201 char human_readable_error[AV_ERROR_MAX_STRING_SIZE]{0};
202 av_make_error_string(human_readable_error, AV_ERROR_MAX_STRING_SIZE,
203 av_errnum);
204 error << "what: " << what << "; error: " << human_readable_error;
205
206 // Dispatch to either the fatal error handler, or the one for decode errors,
207 // as appropriate.
208 switch (av_errnum) {
209 case AVERROR_EOF:
210 case AVERROR(EINVAL):
211 case AVERROR(ENOMEM):
212 client_->OnFatalError(error.str());
213 break;
214 default:
215 client_->OnDecodeError(frame_id, error.str());
216 break;
217 }
218 }
219
220 } // namespace cast
221 } // namespace openscreen
222