#include #include "vlc_producer.h" #include #include #include #include #include using namespace caspar::modules; namespace caspar { namespace vlc { namespace producer { libvlc_instance_t* vlc_producer::vlcInstance = nullptr; vlc_producer::vlc_producer(spl::shared_ptr frame_factory, core::video_format_desc format_desc, ffmpeg_param* param) : frame_factory_(frame_factory) , format_desc_(format_desc) { pixel_data = (uint8_t*)malloc(format_desc_.width * format_desc_.height * 4); if (vlcInstance) { std::string file_name = "file:///" + u8(param->file_name); libvlc_media_t* media = libvlc_media_new_location(file_name.c_str()); media_player = libvlc_media_player_new_from_media(vlcInstance, media); libvlc_media_release(media); libvlc_video_set_callbacks(media_player, video_lock, NULL, video_display, this); libvlc_video_set_format(media_player, "RV32", format_desc.width, format_desc.height, format_desc.width * 4); libvlc_audio_set_callbacks(media_player, audio_play, NULL, NULL, NULL, NULL, this); libvlc_audio_set_format(media_player, "S32N", format_desc.audio_sample_rate, 2); libvlc_media_player_play(media_player); } } vlc_producer::~vlc_producer() { if (media_player) { libvlc_media_player_stop_async(media_player); libvlc_media_player_release(media_player); } } void* vlc_producer::video_lock(void* data, void** planes) { vlc_producer* producer = static_cast(data); *planes = producer->pixel_data; return NULL; } void vlc_producer::audio_play(void* data, const void* samples, unsigned count, int64_t pts) { vlc_producer* producer = static_cast(data); int size = count; uint8_t* buffer = new uint8_t[size]; memcpy(buffer, samples, size); FrameContext frame_context; frame_context.data = buffer; frame_context.nb_samples = count/2; frame_context.pts = pts; frame_context.channels = 2; frame_context.sample_rate = producer->format_desc_.audio_sample_rate; frame_context.audio_format = AVSampleFormat::AV_SAMPLE_FMT_S32; std::lock_guard lock(producer->audio_frames_mutex_); producer->audio_data_.push(frame_context); } void vlc_producer::video_display(void* data, void* picture) { vlc_producer* producer = static_cast(data); FrameContext frame_context; frame_context.data = producer->pixel_data; frame_context.height = producer->format_desc_.height; frame_context.width = producer->format_desc_.width; frame_context.video_format = AVPixelFormat::AV_PIX_FMT_BGRA; frame_context.line_size = producer->format_desc_.width * 4; std::lock_guard lock(producer->video_frames_mutex_); producer->video_data_.push(frame_context); } bool vlc_producer::try_pop(FrameContext& video_frame, FrameContext& audio_frame ) { { std::lock_guard lock(video_frames_mutex_); if (!video_data_.empty()) { video_frame = video_data_.front(); video_frame.valid = true; video_data_.pop(); } } { std::lock_guard lock(audio_frames_mutex_); if (!audio_data_.empty()) { audio_frame = audio_data_.front(); audio_frame.valid = true; audio_data_.pop(); } } return video_frame.valid; } core::draw_frame vlc_producer::receive_impl(const core::video_field field, int nb_samples) { FrameContext video_frame; FrameContext audio_frame; if (try_pop(video_frame, audio_frame)) { std::shared_ptr av_frame(av_frame_alloc(), [](AVFrame* frame) { av_frame_free(&frame); }); std::shared_ptr a_frame(av_frame_alloc(), [](AVFrame* frame) { av_frame_free(&frame); }); av_frame->data[0] = video_frame.data; av_frame->linesize[0] = video_frame.line_size; av_frame->format = video_frame.video_format; av_frame->width = video_frame.width; av_frame->height = video_frame.height; if (audio_frame.valid) { a_frame->channels = audio_frame.channels; a_frame->format = audio_frame.audio_format; a_frame->sample_rate = audio_frame.sample_rate; a_frame->nb_samples = audio_frame.nb_samples; a_frame->data[0] = audio_frame.data; a_frame->pts = audio_frame.pts; a_frame->interlaced_frame = false; a_frame->channel_layout = av_get_default_channel_layout(a_frame->channels); } auto mframe = ffmpeg::make_frame(this, *(frame_factory_.get()), std::move(av_frame), std::move(a_frame)); delete[] audio_frame.data; //delete[] video_frame.data; last_frame_ = core::draw_frame(std::move(mframe)); } return last_frame_; } core::draw_frame vlc_producer::last_frame(const core::video_field field) { return last_frame_; } core::draw_frame vlc_producer::first_frame(const core::video_field field) { return last_frame_; } std::wstring vlc_producer::print() const { return L""; } std::wstring vlc_producer::name() const { return L"vlc"; } core::monitor::state vlc_producer::state() const { return state_; } spl::shared_ptr create_producer(const core::frame_producer_dependencies& dependencies, const std::vector& params) { ffmpeg_param* param = caspar::modules::parse(dependencies, params); if (param != nullptr) { try { auto producer = spl::make_shared(dependencies.frame_factory, dependencies.format_desc, param); return core::create_destroy_proxy(std::move(producer)); } catch (...) { CASPAR_LOG_CURRENT_EXCEPTION(); } } return core::frame_producer::empty(); } }}} // namespace caspar::vlc::producer