diff --git a/src/media/libav_utils.cpp b/src/media/libav_utils.cpp index 9abbfb4a99620f339b78260af12e40dd52f58a97..50f6fbea760c5f03a796140ffd48ad9836adcb5f 100644 --- a/src/media/libav_utils.cpp +++ b/src/media/libav_utils.cpp @@ -4,6 +4,7 @@ * Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com> * Author: Luca Barbato <lu_zero@gentoo.org> * Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com> + * Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -205,6 +206,12 @@ getDictValue(const AVDictionary* d, const std::string& key, int flags) return ""; } +void +setDictValue(AVDictionary** d, const std::string& key, const std::string& value, int flags) +{ + av_dict_set(d, key.c_str(), value.c_str(), flags); +} + void fillWithBlack(AVFrame* frame) { diff --git a/src/media/libav_utils.h b/src/media/libav_utils.h index d898957e6581f9caad659472ca6f3c1d0a5de1d9..8f3d32a59d868029b779c944527c71db6accb494 100644 --- a/src/media/libav_utils.h +++ b/src/media/libav_utils.h @@ -2,6 +2,7 @@ * Copyright (C) 2004-2019 Savoir-faire Linux Inc. * * Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com> + * Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -45,6 +46,8 @@ namespace ring { namespace libav_utils { const char* getDictValue(const AVDictionary* d, const std::string& key, int flags=0); + void setDictValue(AVDictionary** d, const std::string& key, const std::string& value, int flags=0); + void fillWithBlack(AVFrame* frame); void fillWithSilence(AVFrame* frame); diff --git a/src/media/media_encoder.cpp b/src/media/media_encoder.cpp index 038d20e2cd9dc9f32540e35faa9623692ed672af..193869e8cba1414d181315b5aece0face4380215 100644 --- a/src/media/media_encoder.cpp +++ b/src/media/media_encoder.cpp @@ -3,6 +3,7 @@ * * Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com> * Author: Eloi Bail <Eloi.Bail@savoirfairelinux.com> + * Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -76,39 +77,39 @@ void MediaEncoder::setDeviceOptions(const DeviceParams& args) device_.width -= device_.width % 2; device_.height -= device_.height % 2; if (device_.width) - av_dict_set(&options_, "width", ring::to_string(device_.width).c_str(), 0); + libav_utils::setDictValue(&options_, "width", ring::to_string(device_.width)); if (device_.height) - av_dict_set(&options_, "height", ring::to_string(device_.height).c_str(), 0); + libav_utils::setDictValue(&options_, "height", ring::to_string(device_.height)); if (not device_.framerate) device_.framerate = 30; - av_dict_set(&options_, "framerate", ring::to_string(device_.framerate.real()).c_str(), 0); + libav_utils::setDictValue(&options_, "framerate", ring::to_string(device_.framerate.real())); } void MediaEncoder::setOptions(const MediaDescription& args) { codec_ = args.codec; - av_dict_set(&options_, "payload_type", ring::to_string(args.payload_type).c_str(), 0); - av_dict_set(&options_, "max_rate", ring::to_string(args.codec->bitrate).c_str(), 0); - av_dict_set(&options_, "crf", ring::to_string(args.codec->quality).c_str(), 0); + libav_utils::setDictValue(&options_, "payload_type", ring::to_string(args.payload_type)); + libav_utils::setDictValue(&options_, "max_rate", ring::to_string(args.codec->bitrate)); + libav_utils::setDictValue(&options_, "crf", ring::to_string(args.codec->quality)); if (args.codec->systemCodecInfo.mediaType == MEDIA_AUDIO) { auto accountAudioCodec = std::static_pointer_cast<AccountAudioCodecInfo>(args.codec); if (accountAudioCodec->audioformat.sample_rate) - av_dict_set(&options_, "sample_rate", - ring::to_string(accountAudioCodec->audioformat.sample_rate).c_str(), 0); + libav_utils::setDictValue(&options_, "sample_rate", + ring::to_string(accountAudioCodec->audioformat.sample_rate)); if (accountAudioCodec->audioformat.nb_channels) - av_dict_set(&options_, "channels", - ring::to_string(accountAudioCodec->audioformat.nb_channels).c_str(), 0); + libav_utils::setDictValue(&options_, "channels", + ring::to_string(accountAudioCodec->audioformat.nb_channels)); if (accountAudioCodec->audioformat.sample_rate && accountAudioCodec->audioformat.nb_channels) - av_dict_set(&options_, "frame_size", - ring::to_string(static_cast<unsigned>(0.02 * accountAudioCodec->audioformat.sample_rate)).c_str(), 0); + libav_utils::setDictValue(&options_, "frame_size", + ring::to_string(static_cast<unsigned>(0.02 * accountAudioCodec->audioformat.sample_rate))); } if (not args.parameters.empty()) - av_dict_set(&options_, "parameters", args.parameters.c_str(), 0); + libav_utils::setDictValue(&options_, "parameters", args.parameters); } void @@ -116,7 +117,7 @@ MediaEncoder::setInitSeqVal(uint16_t seqVal) { //only set not default value (!=0) if (seqVal != 0) - av_dict_set(&options_, "seq", ring::to_string(seqVal).c_str(), 0); + libav_utils::setDictValue(&options_, "seq", ring::to_string(seqVal)); } uint16_t @@ -168,9 +169,9 @@ MediaEncoder::openFileOutput(const std::string& filename, std::map<std::string, avformat_alloc_output_context2(&outputCtx_, nullptr, nullptr, filename.c_str()); if (!options["title"].empty()) - av_dict_set(&outputCtx_->metadata, "title", options["title"].c_str(), 0); + libav_utils::setDictValue(&outputCtx_->metadata, "title", options["title"]); if (!options["description"].empty()) - av_dict_set(&outputCtx_->metadata, "description", options["description"].c_str(), 0); + libav_utils::setDictValue(&outputCtx_->metadata, "description", options["description"]); auto bitrate = SystemCodecInfo::DEFAULT_MAX_BITRATE; auto quality = SystemCodecInfo::DEFAULT_CODEC_QUALITY; @@ -185,7 +186,7 @@ MediaEncoder::openFileOutput(const std::string& filename, std::map<std::string, options.insert({"height", "240"}); options.insert({"framerate", "30.00"}); for (const auto& it : options) - av_dict_set(&options_, it.first.c_str(), it.second.c_str(), 0); + libav_utils::setDictValue(&options_, it.first, it.second); // for a file output, addStream is done by the caller, as there may be multiple streams } @@ -498,17 +499,16 @@ AVCodecContext* MediaEncoder::prepareEncoderContext(AVCodec* outputCodec, bool i // satisfy ffmpeg: denominator must be 16bit or less value // time base = 1/FPS if (device_.framerate) { - av_dict_set(&options_, "width", ring::to_string(device_.width).c_str(), 0); av_reduce(&encoderCtx->framerate.num, &encoderCtx->framerate.den, device_.framerate.numerator(), device_.framerate.denominator(), (1U << 16) - 1); encoderCtx->time_base = av_inv_q(encoderCtx->framerate); } else { // get from options_, else default to 30 fps - auto v = av_dict_get(options_, "framerate", nullptr, 0); + auto v = libav_utils::getDictValue(options_, "framerate"); AVRational framerate = AVRational{30, 1}; if (v) - av_parse_ratio_quiet(&framerate, v->value, 120); + av_parse_ratio_quiet(&framerate, v, 120); if (framerate.den == 0) framerate.den = 1; av_reduce(&encoderCtx->framerate.num, &encoderCtx->framerate.den, @@ -528,18 +528,18 @@ AVCodecContext* MediaEncoder::prepareEncoderContext(AVCodec* outputCodec, bool i // encoderCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; } else { encoderCtx->sample_fmt = AV_SAMPLE_FMT_S16; - auto v = av_dict_get(options_, "sample_rate", nullptr, 0); + auto v = libav_utils::getDictValue(options_, "sample_rate"); if (v) { - encoderCtx->sample_rate = atoi(v->value); + encoderCtx->sample_rate = atoi(v); encoderCtx->time_base = AVRational{1, encoderCtx->sample_rate}; } else { RING_WARN("[%s] No sample rate set", encoderName); encoderCtx->sample_rate = 8000; } - v = av_dict_get(options_, "channels", nullptr, 0); + v = libav_utils::getDictValue(options_, "channels"); if (v) { - auto c = std::atoi(v->value); + auto c = std::atoi(v); if (c > 2 or c < 1) { RING_WARN("[%s] Clamping invalid channel value %d", encoderName, c); c = 1; @@ -552,9 +552,9 @@ AVCodecContext* MediaEncoder::prepareEncoderContext(AVCodec* outputCodec, bool i encoderCtx->channel_layout = encoderCtx->channels == 2 ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO; - v = av_dict_get(options_, "frame_size", nullptr, 0); + v = libav_utils::getDictValue(options_, "frame_size"); if (v) { - encoderCtx->frame_size = atoi(v->value); + encoderCtx->frame_size = atoi(v); RING_DBG("[%s] Frame size %d", encoderName, encoderCtx->frame_size); } else { RING_WARN("[%s] Frame size not set", encoderName); diff --git a/src/media/media_encoder.h b/src/media/media_encoder.h index fc19262d211c02bc95d3aea9a9e69af6236ad771..8791ed035ec53f82d137a7939715317ff86a9f54 100644 --- a/src/media/media_encoder.h +++ b/src/media/media_encoder.h @@ -2,6 +2,7 @@ * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * * Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com> + * Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by