diff --git a/src/media/Makefile.am b/src/media/Makefile.am index c216e36c44eed10344795d781df40226c307127f..50944f3e09f0dda748ce50d67778c00730441aa5 100644 --- a/src/media/Makefile.am +++ b/src/media/Makefile.am @@ -33,7 +33,8 @@ noinst_HEADERS = \ media_codec.h \ system_codec_container.h \ srtp.h \ - recordable.h + recordable.h \ + decoder_finder.h libmedia_la_LIBADD = \ ./audio/libaudio.la diff --git a/src/media/video/decoder_finder.h b/src/media/decoder_finder.h similarity index 96% rename from src/media/video/decoder_finder.h rename to src/media/decoder_finder.h index 7fdcbbc614c703af295d592453c442048926485f..6ddac6d9cc30fd4886413ce9ea7b085efbb68c13 100644 --- a/src/media/video/decoder_finder.h +++ b/src/media/decoder_finder.h @@ -23,7 +23,7 @@ extern "C" { #include <libavcodec/avcodec.h> } -namespace ring { namespace video { +namespace ring { /** * Attempt to find standalone AVCodec decoder using AVCodecID, @@ -57,4 +57,4 @@ findDecoder(const enum AVCodecID codec_id) return codec; } -}} // namespace ring::video +} // namespace ring diff --git a/src/media/media_decoder.cpp b/src/media/media_decoder.cpp index de1799ffc2655ccb6010a22c30c8615b503e1e7f..974833068086b9ab564577f49aea5515ef384adb 100644 --- a/src/media/media_decoder.cpp +++ b/src/media/media_decoder.cpp @@ -26,7 +26,7 @@ #include "audio/audiobuffer.h" #include "audio/ringbuffer.h" #include "audio/resampler.h" -#include "video/decoder_finder.h" +#include "decoder_finder.h" #include "manager.h" #ifdef RING_ACCEL @@ -148,169 +148,71 @@ void MediaDecoder::setIOContext(MediaIOHandle *ioctx) int MediaDecoder::setupFromAudioData(const AudioFormat format) { - int ret; - - if (decoderCtx_) - avcodec_close(decoderCtx_); - - // Increase analyze time to solve synchronization issues between callers. - static const unsigned MAX_ANALYZE_DURATION = 30; // time in seconds - - inputCtx_->max_analyze_duration = MAX_ANALYZE_DURATION * AV_TIME_BASE; - - RING_DBG("Finding stream info"); - ret = avformat_find_stream_info(inputCtx_, NULL); - RING_DBG("Finding stream info DONE"); - - if (ret < 0) { - char errBuf[64] = {0}; - // print nothing for unknown errors - if (av_strerror(ret, errBuf, sizeof errBuf) < 0) - errBuf[0] = '\0'; - - // always fail here - RING_ERR("Could not find stream info: %s", errBuf); - return -1; - } - - // find the first audio stream from the input - for (size_t i = 0; streamIndex_ == -1 && i < inputCtx_->nb_streams; ++i) -#ifndef _WIN32 - if (inputCtx_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) -#else - if (inputCtx_->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) -#endif - streamIndex_ = i; - - if (streamIndex_ == -1) { - RING_ERR("Could not find audio stream"); - return -1; - } - - // Get a pointer to the codec context for the video stream - avStream_ = inputCtx_->streams[streamIndex_]; -#ifndef _WIN32 - inputDecoder_ = avcodec_find_decoder(avStream_->codecpar->codec_id); - if (!inputDecoder_) { - RING_ERR("Unsupported codec"); - return -1; - } - - decoderCtx_ = avcodec_alloc_context3(inputDecoder_); - avcodec_parameters_to_context(decoderCtx_, avStream_->codecpar); -#else - decoderCtx_ = avStream_->codec; - if (decoderCtx_ == 0) { - RING_ERR("Decoder context is NULL"); - return -1; - } - - // find the decoder for the audio stream - inputDecoder_ = avcodec_find_decoder(decoderCtx_->codec_id); - if (!inputDecoder_) { - RING_ERR("Unsupported codec"); - return -1; - } -#endif - - decoderCtx_->thread_count = std::max(1u, std::min(8u, std::thread::hardware_concurrency()/2)); - decoderCtx_->channels = format.nb_channels; - decoderCtx_->sample_rate = format.sample_rate; - - RING_DBG("Audio decoding using %s with %s", - inputDecoder_->name, format.toString().c_str()); - - if (emulateRate_) { - RING_DBG("Using framerate emulation"); - startTime_ = av_gettime(); - } - - ret = avcodec_open2(decoderCtx_, inputDecoder_, NULL); - if (ret) { - RING_ERR("Could not open codec"); - return -1; - } - - return 0; + // Use AVDictionary to send extra arguments to setupStream, since video setup doesn't need them + av_dict_set_int(&options_, "nb_channels", format.nb_channels, 0); + av_dict_set_int(&options_, "sample_rate", format.sample_rate, 0); + return setupStream(AVMEDIA_TYPE_AUDIO); } -#ifdef RING_VIDEO -int MediaDecoder::setupFromVideoData() +int +MediaDecoder::setupStream(AVMediaType mediaType) { int ret = 0; + std::string streamType = av_get_media_type_string(mediaType); - if (decoderCtx_) - avcodec_close(decoderCtx_); + avcodec_free_context(&decoderCtx_); // Increase analyze time to solve synchronization issues between callers. - static const unsigned MAX_ANALYZE_DURATION = 30; // time in seconds - + static const unsigned MAX_ANALYZE_DURATION = 30; inputCtx_->max_analyze_duration = MAX_ANALYZE_DURATION * AV_TIME_BASE; - // if fallback from accel, don't check for stream info, it's already done + + // If fallback from accel, don't check for stream info, it's already done if (!fallback_) { - RING_DBG("Finding stream info"); - ret = avformat_find_stream_info(inputCtx_, NULL); - } - if (ret < 0) { - // workaround for this bug: - // http://patches.libav.org/patch/22541/ - if (ret == -1) - ret = AVERROR_INVALIDDATA; - char errBuf[64] = {0}; - // print nothing for unknown errors - if (av_strerror(ret, errBuf, sizeof errBuf) < 0) - errBuf[0] = '\0'; - - // always fail here - RING_ERR("Could not find stream info: %s", errBuf); - return -1; + RING_DBG() << "Finding " << streamType << " stream info"; + if ((ret = avformat_find_stream_info(inputCtx_, nullptr)) < 0) { + char errBuf[64]; + av_strerror(ret, errBuf, sizeof(errBuf)); + + // Always fail here + RING_ERR() << "Could not find " << streamType << " stream info: " << errBuf; + return -1; + } } - // find the first video stream from the input - for (size_t i = 0; streamIndex_ == -1 && i < inputCtx_->nb_streams; ++i) -#ifndef _WIN32 - if (inputCtx_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) -#else - if (inputCtx_->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) -#endif + for (size_t i = 0; streamIndex_ == -1 && i < inputCtx_->nb_streams; ++i) { + if (inputCtx_->streams[i]->codecpar->codec_type == mediaType) { streamIndex_ = i; + } + } - if (streamIndex_ == -1) { - RING_ERR("Could not find video stream"); + if (streamIndex_ < 0) { + RING_ERR() << "No " << streamType << " stream found"; return -1; } - // Get a pointer to the codec context for the video stream avStream_ = inputCtx_->streams[streamIndex_]; -#ifndef _WIN32 - inputDecoder_ = video::findDecoder(avStream_->codecpar->codec_id); + + inputDecoder_ = findDecoder(avStream_->codecpar->codec_id); if (!inputDecoder_) { - RING_ERR("Unsupported codec"); + RING_ERR() << "Unsupported codec"; return -1; } decoderCtx_ = avcodec_alloc_context3(inputDecoder_); - avcodec_parameters_to_context(decoderCtx_, avStream_->codecpar); -#else - decoderCtx_ = avStream_->codec; - if (decoderCtx_ == 0) { - RING_ERR("Decoder context is NULL"); + if (!decoderCtx_) { + RING_ERR() << "Failed to create decoder context"; return -1; } - - // find the decoder for the video stream - inputDecoder_ = avcodec_find_decoder(decoderCtx_->codec_id); - if (!inputDecoder_) { - RING_ERR("Unsupported codec"); - return -1; - } -#endif - RING_DBG("Decoding video using %s (%s)", inputDecoder_->long_name, inputDecoder_->name); + avcodec_parameters_to_context(decoderCtx_, avStream_->codecpar); decoderCtx_->thread_count = std::max(1u, std::min(8u, std::thread::hardware_concurrency()/2)); + if (mediaType == AVMEDIA_TYPE_AUDIO) { + decoderCtx_->channels = std::stoi(av_dict_get(options_, "nb_channels", nullptr, 0)->value); + decoderCtx_->sample_rate = std::stoi(av_dict_get(options_, "sample_rate", nullptr, 0)->value); + } if (emulateRate_) { - RING_DBG("Using framerate emulation"); + RING_DBG() << "Using framerate emulation"; startTime_ = av_gettime(); } @@ -319,21 +221,31 @@ int MediaDecoder::setupFromVideoData() accel_ = video::setupHardwareDecoding(decoderCtx_); decoderCtx_->opaque = &accel_; } else if (Manager::instance().getDecodingAccelerated()) { - RING_WARN("Hardware accelerated decoding disabled because of previous failure"); + RING_WARN() << "Hardware accelerated decoding disabled because of previous failure"; } else { - RING_WARN("Hardware accelerated decoding disabled by user preference"); + RING_WARN() << "Hardware accelerated decoding disabled by user preference"; } #endif - ret = avcodec_open2(decoderCtx_, inputDecoder_, NULL); - if (ret) { - RING_ERR("Could not open codec"); + RING_DBG() << "Decoding " << streamType << " using " << inputDecoder_->long_name << " (" << inputDecoder_->name << ")"; + + ret = avcodec_open2(decoderCtx_, inputDecoder_, nullptr); + if (ret < 0) { + char errBuf[64]; + av_strerror(ret, errBuf, sizeof(errBuf)); + RING_ERR() << "Could not open codec: " << errBuf; return -1; } return 0; } +#ifdef RING_VIDEO +int MediaDecoder::setupFromVideoData() +{ + return setupStream(AVMEDIA_TYPE_VIDEO); +} + MediaDecoder::Status MediaDecoder::decode(VideoFrame& result) { diff --git a/src/media/media_decoder.h b/src/media/media_decoder.h index 524474f09a2e80c354a4286385a9784e174c5281..71fdcc0c02ded22d7eea3334d9b1880e673c978e 100644 --- a/src/media/media_decoder.h +++ b/src/media/media_decoder.h @@ -45,6 +45,7 @@ class AVStream; class AVDictionary; class AVFormatContext; class AVCodec; +enum AVMediaType; namespace ring { @@ -115,6 +116,7 @@ class MediaDecoder { void extract(const std::map<std::string, std::string>& map, const std::string& key); int correctPixFmt(int input_pix_fmt); + int setupStream(AVMediaType mediaType); bool fallback_ = false; diff --git a/src/media/video/Makefile.am b/src/media/video/Makefile.am index 4617b906d7e698f6ce63686920373c801f6236ea..bd3abf7337bbcbbcc42eb5324f5c32d7d6b2f25a 100644 --- a/src/media/video/Makefile.am +++ b/src/media/video/Makefile.am @@ -36,8 +36,7 @@ libvideo_la_SOURCES = \ video_receive_thread.cpp video_receive_thread.h \ video_sender.cpp video_sender.h \ video_rtp_session.cpp video_rtp_session.h \ - sinkclient.cpp sinkclient.h \ - decoder_finder.h + sinkclient.cpp sinkclient.h if RING_ACCEL libvideo_la_SOURCES += accel.cpp accel.h