17 #include <glog/logging.h> 20 #include <unordered_map> 32 #define LogError(code, extra_info) \ 33 LOG(ERROR) << (*(extra_info) = \ 34 std::string("Error from FFmpeg: ") + av_err2str(code)) 35 #define ALLOC_ERROR_STR "Error allocating memory" 37 const AVCodec* FindCodec(
const std::string& codec_name) {
38 #ifdef ENABLE_HARDWARE_DECODE 39 const AVCodec* hybrid =
nullptr;
40 const AVCodec* external =
nullptr;
41 void* opaque =
nullptr;
42 while (
const AVCodec* codec = av_codec_iterate(&opaque)) {
43 if (avcodec_get_name(codec->id) == codec_name &&
44 av_codec_is_decoder(codec)) {
45 if (codec->capabilities & AV_CODEC_CAP_HARDWARE)
48 if (codec->capabilities & AV_CODEC_CAP_HYBRID) {
51 }
else if (codec->wrapper_name) {
63 return avcodec_find_decoder_by_name(codec_name.c_str());
66 std::string GetCodecFromMime(
const std::string& mime) {
67 std::unordered_map<std::string, std::string> params;
71 return it != params.end() ? it->second :
"";
77 : mutex_(
"FFmpegDecoder"),
78 decoder_ctx_(nullptr),
79 received_frame_(nullptr),
80 #ifdef ENABLE_HARDWARE_DECODE
81 hw_device_ctx_(nullptr),
82 hw_pix_fmt_(AV_PIX_FMT_NONE),
84 prev_timestamp_offset_(0) {
89 avcodec_free_context(&decoder_ctx_);
90 av_frame_free(&received_frame_);
91 #ifdef ENABLE_HARDWARE_DECODE 92 av_buffer_unref(&hw_device_ctx_);
104 const std::string codec = GetCodecFromMime(
108 ret.
supported = codec.empty() || c !=
nullptr;
114 std::unique_lock<Mutex> lock(mutex_);
115 avcodec_free_context(&decoder_ctx_);
120 std::vector<std::shared_ptr<DecodedFrame>>*
frames,
121 std::string* extra_info) {
122 std::unique_lock<Mutex> lock(mutex_);
123 if (!input && !decoder_ctx_) {
129 if (!decoder_ctx_ || input->stream_info != decoder_stream_info_) {
130 VLOG(1) <<
"Reconfiguring decoder";
133 const int send_code = avcodec_send_packet(decoder_ctx_,
nullptr);
134 if (send_code != 0) {
138 if (!ReadFromDecoder(decoder_stream_info_,
nullptr,
frames, extra_info))
142 if (!InitializeDecoder(input->stream_info,
true, extra_info))
146 prev_timestamp_offset_ = input->timestamp_offset;
152 util::Finally free_decrypted_packet(std::bind(&av_packet_unref, &packet));
153 if (input && input->encryption_info) {
155 LOG(WARNING) << (*extra_info =
"No CDM given for encrypted frame");
159 int code = av_new_packet(&packet, input->data_size);
165 MediaStatus decrypt_status = input->Decrypt(eme, packet.data);
169 *extra_info =
"CDM returned error while decrypting frame";
173 const double timescale = input->stream_info->time_scale;
174 packet.pts =
static_cast<int64_t
>(input->pts / timescale);
175 packet.dts =
static_cast<int64_t
>(input->dts / timescale);
176 packet.data =
const_cast<uint8_t*
>(input->data);
177 packet.size = input->data_size;
180 bool sent_frame =
false;
181 while (!sent_frame) {
183 const int send_code = avcodec_send_packet(decoder_ctx_, &packet);
184 if (send_code == 0) {
186 }
else if (send_code == AVERROR_EOF) {
189 avcodec_free_context(&decoder_ctx_);
191 }
else if (send_code != AVERROR(EAGAIN)) {
196 auto stream_info = input ? input->stream_info : decoder_stream_info_;
197 if (!ReadFromDecoder(stream_info, input,
frames, extra_info))
204 #ifdef ENABLE_HARDWARE_DECODE 205 AVPixelFormat FFmpegDecoder::GetPixelFormat(AVCodecContext* ctx,
206 const AVPixelFormat* formats) {
207 AVPixelFormat desired =
209 for (
size_t i = 0; formats[i] != AV_PIX_FMT_NONE; i++) {
210 if (formats[i] == desired)
213 # ifdef FORCE_HARDWARE_DECODE 214 LOG(DFATAL) <<
"Hardware pixel format is unsupported.";
215 return AV_PIX_FMT_NONE;
217 LOG(ERROR) <<
"Hardware pixel format is unsupported, may be falling back " 218 "to software decoder.";
224 bool FFmpegDecoder::InitializeDecoder(std::shared_ptr<const StreamInfo> info,
226 std::string* extra_info) {
227 const AVCodec* decoder =
230 : avcodec_find_decoder_by_name(
NormalizeCodec(info->codec).c_str());
231 CHECK(decoder) <<
"Should have checked support already";
232 #ifdef ENABLE_HARDWARE_DECODE 233 AVHWDeviceType hw_type = AV_HWDEVICE_TYPE_NONE;
234 hw_pix_fmt_ = AV_PIX_FMT_NONE;
235 if (allow_hardware) {
236 for (
int i = 0;; i++) {
237 const AVCodecHWConfig* config = avcodec_get_hw_config(decoder, i);
239 # ifdef FORCE_HARDWARE_DECODE 240 if (!decoder->wrapper_name) {
242 "No hardware-accelerators available for codec: " + info->codec;
243 LOG(DFATAL) << *extra_info;
247 LOG(INFO) <<
"No hardware-accelerators available, using decoder: " 252 if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) {
253 LOG(INFO) <<
"Using decoder: " << decoder->name
254 <<
", with hardware accelerator: " 255 << av_hwdevice_get_type_name(config->device_type);
256 hw_type = config->device_type;
257 hw_pix_fmt_ = config->pix_fmt;
264 avcodec_free_context(&decoder_ctx_);
265 decoder_ctx_ = avcodec_alloc_context3(decoder);
271 if (!received_frame_) {
272 received_frame_ = av_frame_alloc();
273 if (!received_frame_) {
279 decoder_ctx_->thread_count = 0;
280 decoder_ctx_->opaque =
this;
281 decoder_ctx_->pkt_timebase = {.num = info->time_scale.numerator,
282 .den = info->time_scale.denominator};
284 if (!info->extra_data.empty()) {
285 av_freep(&decoder_ctx_->extradata);
286 decoder_ctx_->extradata =
reinterpret_cast<uint8_t*
>(
287 av_mallocz(info->extra_data.size() + AV_INPUT_BUFFER_PADDING_SIZE));
288 if (!decoder_ctx_->extradata) {
292 memcpy(decoder_ctx_->extradata, info->extra_data.data(),
293 info->extra_data.size());
294 decoder_ctx_->extradata_size = info->extra_data.size();
297 #ifdef ENABLE_HARDWARE_DECODE 299 av_buffer_unref(&hw_device_ctx_);
300 if (allow_hardware && hw_type != AV_HWDEVICE_TYPE_NONE) {
301 const int hw_device_code =
302 av_hwdevice_ctx_create(&hw_device_ctx_, hw_type,
nullptr,
nullptr, 0);
303 if (hw_device_code < 0) {
304 LogError(hw_device_code, extra_info);
307 decoder_ctx_->get_format = &GetPixelFormat;
308 decoder_ctx_->hw_device_ctx = av_buffer_ref(hw_device_ctx_);
312 const int open_code = avcodec_open2(decoder_ctx_, decoder,
nullptr);
314 if (open_code == AVERROR(ENOMEM)) {
318 #if defined(ENABLE_HARDWARE_DECODE) && !defined(FORCE_HARDWARE_DECODE) 319 if (allow_hardware) {
320 LOG(WARNING) <<
"Failed to initialize hardware decoder, falling back " 322 return InitializeDecoder(info,
false, extra_info);
330 decoder_stream_info_ = info;
334 bool FFmpegDecoder::ReadFromDecoder(
335 std::shared_ptr<const StreamInfo> stream_info,
336 std::shared_ptr<EncodedFrame> input,
337 std::vector<std::shared_ptr<DecodedFrame>>* decoded,
338 std::string* extra_info) {
340 const int code = avcodec_receive_frame(decoder_ctx_, received_frame_);
341 if (code == AVERROR(EAGAIN) || code == AVERROR_EOF)
348 const double timescale = stream_info->time_scale;
349 const int64_t timestamp = received_frame_->best_effort_timestamp;
350 const double offset =
351 input ? input->timestamp_offset : prev_timestamp_offset_;
352 const double time = input && timestamp == AV_NOPTS_VALUE
354 : timestamp * timescale + offset;
356 stream_info, received_frame_, time, input ? input->duration : 0);
361 decoded->emplace_back(new_frame);
std::list< std::shared_ptr< BaseFrame > > frames
#define LogError(code, extra_info)