int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
{
AVClass* av_class = *(AVClass**)obj;
if((strcmp(name, "pix_fmt") == 0 || strcmp(name, "pixel_format") == 0) && strcmp(av_class->class_name, "AVCodecContext") == 0)
{
int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
{
AVClass* av_class = *(AVClass**)obj;
if((strcmp(name, "pix_fmt") == 0 || strcmp(name, "pixel_format") == 0) && strcmp(av_class->class_name, "AVCodecContext") == 0)
{
c->pix_fmt = pix_fmt;
return 0;
}
//if((strcmp(name, "r") == 0 || strcmp(name, "frame_rate") == 0) && strcmp(av_class->class_name, "AVCodecContext") == 0)
//{
c->pix_fmt = pix_fmt;
return 0;
}
//if((strcmp(name, "r") == 0 || strcmp(name, "frame_rate") == 0) && strcmp(av_class->class_name, "AVCodecContext") == 0)
//{
if(vcodec == CODEC_ID_NONE && format)
vcodec = format->video_codec;
if(acodec == CODEC_ID_NONE && format)
acodec = format->audio_codec;
if(vcodec == CODEC_ID_NONE && format)
vcodec = format->video_codec;
if(acodec == CODEC_ID_NONE && format)
acodec = format->audio_codec;
// enum { PAL, NTSC, FILM, UNKNOWN } norm = UNKNOWN;
// enum { PAL, NTSC, FILM, UNKNOWN } norm = UNKNOWN;
{
if(av_parse_video_size(&width, &height, value.c_str()) < 0)
CASPAR_THROW_EXCEPTION(user_error() << msg_info("Unknown video size " + value));
{
if(av_parse_video_size(&width, &height, value.c_str()) < 0)
CASPAR_THROW_EXCEPTION(user_error() << msg_info("Unknown video size " + value));
const spl::shared_ptr<diagnostics::graph> graph_;
const std::string filename_;
const std::string full_filename_ = u8(env::media_folder()) + filename_;
const spl::shared_ptr<diagnostics::graph> graph_;
const std::string filename_;
const std::string full_filename_ = u8(env::media_folder()) + filename_;
byte_vector picture_buffer_;
byte_vector key_picture_buf_;
byte_vector audio_buffer_;
byte_vector picture_buffer_;
byte_vector key_picture_buf_;
byte_vector audio_buffer_;
// Add the audio and video streams using the default format codecs and initialize the codecs.
video_st_ = add_video_stream(options);
if (!key_only)
audio_st_ = add_audio_stream(options);
// Add the audio and video streams using the default format codecs and initialize the codecs.
video_st_ = add_video_stream(options);
if (!key_only)
audio_st_ = add_audio_stream(options);
av_dump_format(oc_.get(), 0, full_filename_.c_str(), 1);
av_dump_format(oc_.get(), 0, full_filename_.c_str(), 1);
THROW_ON_ERROR2(avio_open(&oc_->pb, full_filename_.c_str(), AVIO_FLAG_WRITE), "[ffmpeg_consumer]");
THROW_ON_ERROR2(avio_open(&oc_->pb, full_filename_.c_str(), AVIO_FLAG_WRITE), "[ffmpeg_consumer]");
if(output_format_.vcodec == CODEC_ID_NONE)
return nullptr;
auto st = avformat_new_stream(oc_.get(), 0);
if(output_format_.vcodec == CODEC_ID_NONE)
return nullptr;
auto st = avformat_new_stream(oc_.get(), 0);
c->codec_id = output_format_.vcodec;
c->codec_type = AVMEDIA_TYPE_VIDEO;
c->width = output_format_.width;
c->codec_id = output_format_.vcodec;
c->codec_type = AVMEDIA_TYPE_VIDEO;
c->width = output_format_.width;
c->pix_fmt = c->pix_fmt != PIX_FMT_NONE ? c->pix_fmt : PIX_FMT_YUV420P;
if(c->codec_id == CODEC_ID_PRORES)
c->pix_fmt = c->pix_fmt != PIX_FMT_NONE ? c->pix_fmt : PIX_FMT_YUV420P;
if(c->codec_id == CODEC_ID_PRORES)
c->bit_rate = output_format_.width < 1280 ? 63*1000000 : 220*1000000;
c->pix_fmt = PIX_FMT_YUV422P10;
}
c->bit_rate = output_format_.width < 1280 ? 63*1000000 : 220*1000000;
c->pix_fmt = PIX_FMT_YUV422P10;
}
av_opt_set(c->priv_data, "preset", "ultrafast", 0);
av_opt_set(c->priv_data, "tune", "fastdecode", 0);
av_opt_set(c->priv_data, "crf", "5", 0);
av_opt_set(c->priv_data, "preset", "ultrafast", 0);
av_opt_set(c->priv_data, "tune", "fastdecode", 0);
av_opt_set(c->priv_data, "crf", "5", 0);
boost::range::remove_erase_if(options, [&](const option& o)
{
return o.name.at(0) != 'a' && ffmpeg::av_opt_set(c, o.name.c_str(), o.value.c_str(), AV_OPT_SEARCH_CHILDREN) > -1;
});
boost::range::remove_erase_if(options, [&](const option& o)
{
return o.name.at(0) != 'a' && ffmpeg::av_opt_set(c, o.name.c_str(), o.value.c_str(), AV_OPT_SEARCH_CHILDREN) > -1;
});
THROW_ON_ERROR2(tbb_avcodec_open(c, encoder, false), "[ffmpeg_consumer]");
return std::shared_ptr<AVStream>(st, [](AVStream* st)
THROW_ON_ERROR2(tbb_avcodec_open(c, encoder, false), "[ffmpeg_consumer]");
return std::shared_ptr<AVStream>(st, [](AVStream* st)
std::shared_ptr<AVStream> add_audio_stream(std::vector<option>& options)
{
if(output_format_.acodec == CODEC_ID_NONE)
std::shared_ptr<AVStream> add_audio_stream(std::vector<option>& options)
{
if(output_format_.acodec == CODEC_ID_NONE)
auto encoder = avcodec_find_encoder(output_format_.acodec);
if (!encoder)
CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("codec not found"));
auto encoder = avcodec_find_encoder(output_format_.acodec);
if (!encoder)
CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("codec not found"));
boost::range::remove_erase_if(options, [&](const option& o)
{
return ffmpeg::av_opt_set(c, o.name.c_str(), o.value.c_str(), AV_OPT_SEARCH_CHILDREN) > -1;
boost::range::remove_erase_if(options, [&](const option& o)
{
return ffmpeg::av_opt_set(c, o.name.c_str(), o.value.c_str(), AV_OPT_SEARCH_CHILDREN) > -1;
auto av_frame = convert_video(frame, enc);
av_frame->interlaced_frame = format_desc_.field_mode != core::field_mode::progressive;
av_frame->top_field_first = format_desc_.field_mode == core::field_mode::upper;
auto av_frame = convert_video(frame, enc);
av_frame->interlaced_frame = format_desc_.field_mode != core::field_mode::progressive;
av_frame->top_field_first = format_desc_.field_mode == core::field_mode::upper;
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts = av_rescale_q(pkt.pts, enc->time_base, video_st_->time_base);
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts = av_rescale_q(pkt.dts, enc->time_base, video_st_->time_base);
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts = av_rescale_q(pkt.pts, enc->time_base, video_st_->time_base);
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts = av_rescale_q(pkt.dts, enc->time_base, video_st_->time_base);
uint64_t get_channel_layout(AVCodecContext* dec)
{
auto layout = (dec->channel_layout && dec->channels == av_get_channel_layout_nb_channels(dec->channel_layout)) ? dec->channel_layout : av_get_default_channel_layout(dec->channels);
return layout;
}
uint64_t get_channel_layout(AVCodecContext* dec)
{
auto layout = (dec->channel_layout && dec->channels == av_get_channel_layout_nb_channels(dec->channel_layout)) ? dec->channel_layout : av_get_default_channel_layout(dec->channels);
return layout;
}
auto enc = audio_st_->codec;
boost::push_back(audio_buffer_, convert_audio(frame, enc));
auto enc = audio_st_->codec;
boost::push_back(audio_buffer_, convert_audio(frame, enc));
THROW_ON_ERROR2(avcodec_fill_audio_frame(av_frame.get(), enc->channels, enc->sample_fmt, audio_buffer_.data(), frame_size, 1), "[ffmpeg_consumer]");
int got_packet = 0;
THROW_ON_ERROR2(avcodec_encode_audio2(enc, &pkt, av_frame.get(), &got_packet), "[ffmpeg_consumer]");
std::shared_ptr<AVPacket> guard(&pkt, av_free_packet);
THROW_ON_ERROR2(avcodec_fill_audio_frame(av_frame.get(), enc->channels, enc->sample_fmt, audio_buffer_.data(), frame_size, 1), "[ffmpeg_consumer]");
int got_packet = 0;
THROW_ON_ERROR2(avcodec_encode_audio2(enc, &pkt, av_frame.get(), &got_packet), "[ffmpeg_consumer]");
std::shared_ptr<AVPacket> guard(&pkt, av_free_packet);
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts = av_rescale_q(pkt.pts, enc->time_base, audio_st_->time_base);
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts = av_rescale_q(pkt.dts, enc->time_base, audio_st_->time_base);
if (pkt.duration > 0)
pkt.duration = static_cast<int>(av_rescale_q(pkt.duration, enc->time_base, audio_st_->time_base));
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts = av_rescale_q(pkt.pts, enc->time_base, audio_st_->time_base);
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts = av_rescale_q(pkt.dts, enc->time_base, audio_st_->time_base);
if (pkt.duration > 0)
pkt.duration = static_cast<int>(av_rescale_q(pkt.duration, enc->time_base, audio_st_->time_base));
- sws_.reset(sws_getContext(format_desc_.width,
- format_desc_.height - output_format_.croptop - output_format_.cropbot,
+ sws_.reset(sws_getContext(format_desc_.width,
+ format_desc_.height - output_format_.croptop - output_format_.cropbot,
- c->height,
- c->pix_fmt,
- SWS_BICUBIC, nullptr, nullptr, nullptr),
+ c->height,
+ c->pix_fmt,
+ SWS_BICUBIC, nullptr, nullptr, nullptr),
std::shared_ptr<AVFrame> in_frame(avcodec_alloc_frame(), av_free);
auto in_picture = reinterpret_cast<AVPicture*>(in_frame.get());
std::shared_ptr<AVFrame> in_frame(avcodec_alloc_frame(), av_free);
auto in_picture = reinterpret_cast<AVPicture*>(in_frame.get());
av_image_fill_linesizes(out_frame->linesize, c->pix_fmt, c->width);
for(int n = 0; n < 4; ++n)
out_frame->linesize[n] += 32 - (out_frame->linesize[n] % 32); // align
picture_buffer_.resize(av_image_fill_pointers(out_frame->data, c->pix_fmt, c->height, nullptr, out_frame->linesize));
av_image_fill_pointers(out_frame->data, c->pix_fmt, c->height, picture_buffer_.data(), out_frame->linesize);
av_image_fill_linesizes(out_frame->linesize, c->pix_fmt, c->width);
for(int n = 0; n < 4; ++n)
out_frame->linesize[n] += 32 - (out_frame->linesize[n] % 32); // align
picture_buffer_.resize(av_image_fill_pointers(out_frame->data, c->pix_fmt, c->height, nullptr, out_frame->linesize));
av_image_fill_pointers(out_frame->data, c->pix_fmt, c->height, picture_buffer_.data(), out_frame->linesize);
{
swr_ = std::shared_ptr<SwrContext>(swr_alloc_set_opts(nullptr,
get_channel_layout(c), c->sample_fmt, c->sample_rate,
{
swr_ = std::shared_ptr<SwrContext>(swr_alloc_set_opts(nullptr,
get_channel_layout(c), c->sample_fmt, c->sample_rate,
byte_vector buffer(48000);
const uint8_t* in[] = {reinterpret_cast<const uint8_t*>(frame.audio_data().data())};
uint8_t* out[] = {buffer.data()};
byte_vector buffer(48000);
const uint8_t* in[] = {reinterpret_cast<const uint8_t*>(frame.audio_data().data())};
uint8_t* out[] = {buffer.data()};
- auto channel_samples = swr_convert(swr_.get(),
- out, static_cast<int>(buffer.size()) / c->channels / av_get_bytes_per_sample(c->sample_fmt),
+ auto channel_samples = swr_convert(swr_.get(),
+ out, static_cast<int>(buffer.size()) / c->channels / av_get_bytes_per_sample(c->sample_fmt),
lock(exception_mutex_, [&]
{
exception_ = std::current_exception();
lock(exception_mutex_, [&]
{
exception_ = std::current_exception();
void initialize(const core::video_format_desc& format_desc, const core::audio_channel_layout& channel_layout, int) override
{
if(consumer_)
void initialize(const core::video_format_desc& format_desc, const core::audio_channel_layout& channel_layout, int) override
{
if(consumer_)
std::future<bool> send(core::const_frame frame) override
{
bool ready_for_frame = consumer_->ready_for_frame();
std::future<bool> send(core::const_frame frame) override
{
bool ready_for_frame = consumer_->ready_for_frame();
if (ready_for_frame && separate_key_)
ready_for_frame = ready_for_frame && key_only_consumer_->ready_for_frame();
if (ready_for_frame)
{
consumer_->send(frame);
if (ready_for_frame && separate_key_)
ready_for_frame = ready_for_frame && key_only_consumer_->ready_for_frame();
if (ready_for_frame)
{
consumer_->send(frame);
}
auto str = std::accumulate(params2.begin(), params2.end(), std::wstring(), [](const std::wstring& lhs, const std::wstring& rhs) {return lhs + L" " + rhs;});
}
auto str = std::accumulate(params2.begin(), params2.end(), std::wstring(), [](const std::wstring& lhs, const std::wstring& rhs) {return lhs + L" " + rhs;});
boost::wregex path_exp(LR"(\s*FILE(\s(?<PATH>.+\.[^\s]+))?.*)", boost::regex::icase);
boost::wsmatch path;
if(!boost::regex_match(str, path, path_exp))
return core::frame_consumer::empty();
boost::wregex path_exp(LR"(\s*FILE(\s(?<PATH>.+\.[^\s]+))?.*)", boost::regex::icase);
boost::wsmatch path;
if(!boost::regex_match(str, path, path_exp))
return core::frame_consumer::empty();
std::vector<option> options;
for(boost::wsregex_iterator it(str.begin(), str.end(), opt_exp); it != boost::wsregex_iterator(); ++it)
{
auto name = u8(boost::trim_copy(boost::to_lower_copy((*it)["NAME"].str())));
auto value = u8(boost::trim_copy(boost::to_lower_copy((*it)["VALUE"].str())));
std::vector<option> options;
for(boost::wsregex_iterator it(str.begin(), str.end(), opt_exp); it != boost::wsregex_iterator(); ++it)
{
auto name = u8(boost::trim_copy(boost::to_lower_copy((*it)["NAME"].str())));
auto value = u8(boost::trim_copy(boost::to_lower_copy((*it)["VALUE"].str())));
std::vector<option> options;
options.push_back(option("vcodec", u8(codec)));
std::vector<option> options;
options.push_back(option("vcodec", u8(codec)));