• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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