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