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