X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fffmpeg%2Fproducer%2Fvideo%2Fvideo_decoder.cpp;h=bc379a8c0b9378d1aab1517dbef8d9f9e2d1e1f8;hb=70235ae09df45c874e133fd4d3fcc1e6e34e993a;hp=620b62dc2d75144f61037be9f4d59b6d484a50e9;hpb=3d6cb3c7621f3080b7a9ed3eba8487d7aa60d108;p=casparcg diff --git a/modules/ffmpeg/producer/video/video_decoder.cpp b/modules/ffmpeg/producer/video/video_decoder.cpp index 620b62dc2..bc379a8c0 100644 --- a/modules/ffmpeg/producer/video/video_decoder.cpp +++ b/modules/ffmpeg/producer/video/video_decoder.cpp @@ -1,201 +1,178 @@ -/* -* Copyright (c) 2011 Sveriges Television AB -* -* This file is part of CasparCG (www.casparcg.com). -* -* CasparCG is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* CasparCG is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with CasparCG. If not, see . -* -* Author: Robert Nagy, ronag89@gmail.com -*/ - -#include "../../stdafx.h" - -#include "video_decoder.h" - -#include "../util/util.h" - -#include "../../ffmpeg_error.h" - -#include -#include -#include - -#include -#include - -#include - -#if defined(_MSC_VER) -#pragma warning (push) -#pragma warning (disable : 4244) -#endif -extern "C" -{ - #include - #include -} -#if defined(_MSC_VER) -#pragma warning (pop) -#endif - -namespace caspar { namespace ffmpeg { - -struct video_decoder::impl : boost::noncopyable -{ - monitor::basic_subject event_subject_; - int index_; - const std::shared_ptr codec_context_; - - std::queue> packets_; - - const uint32_t nb_frames_; - - const int width_; - const int height_; - bool is_progressive_; - - tbb::atomic file_frame_number_; - -public: - explicit impl() - : nb_frames_(0) - , width_(0) - , height_(0) - , is_progressive_(true) - { - file_frame_number_ = 0; - } - - explicit impl(const spl::shared_ptr& context) - : codec_context_(open_codec(*context, AVMEDIA_TYPE_VIDEO, index_)) - , nb_frames_(static_cast(context->streams[index_]->nb_frames)) - , width_(codec_context_->width) - , height_(codec_context_->height) - { - file_frame_number_ = 0; - } - - void push(const std::shared_ptr& packet) - { - if(!packet) - return; - - if(packet->stream_index == index_ || packet->data == nullptr) - packets_.push(spl::make_shared_ptr(packet)); - } - - std::shared_ptr poll() - { - if(packets_.empty()) - return nullptr; - - auto packet = packets_.front(); - - if(!codec_context_) - { - packets_.pop(); - return packet->data == nullptr ? flush_video() : empty_video(); - } - else - { - if(packet->data == nullptr) - { - if(codec_context_->codec->capabilities & CODEC_CAP_DELAY) - { - auto video = decode(*packet); - if(video) - return video; - } - - packets_.pop(); - file_frame_number_ = static_cast(packet->pos); - avcodec_flush_buffers(codec_context_.get()); - return flush_video(); - } - - packets_.pop(); - return decode(*packet); - } - - } - - std::shared_ptr decode(AVPacket& pkt) - { - std::shared_ptr decoded_frame(avcodec_alloc_frame(), av_free); - - int frame_finished = 0; - THROW_ON_ERROR2(avcodec_decode_video2(codec_context_.get(), decoded_frame.get(), &frame_finished, &pkt), "[video_decocer]"); - - // If a decoder consumes less then the whole packet then something is wrong - // that might be just harmless padding at the end, or a problem with the - // AVParser or demuxer which puted more then one frame in a AVPacket. - - if(frame_finished == 0) - return nullptr; - - is_progressive_ = !decoded_frame->interlaced_frame; - - if(decoded_frame->repeat_pict > 0) - CASPAR_LOG(warning) << "[video_decoder] Field repeat_pict not implemented."; - - event_subject_ << monitor::event("file/video/width") % width_ - << monitor::event("file/video/height") % height_ - << monitor::event("file/video/field") % u8(!decoded_frame->interlaced_frame ? "progressive" : (decoded_frame->top_field_first ? "upper" : "lower")) - << monitor::event("file/video/codec") % u8(codec_context_->codec->long_name); - - ++file_frame_number_; - - return decoded_frame; - } - - bool ready() const - { - return !codec_context_ || !packets_.empty(); - } - - void clear() - { - while(!packets_.empty()) - packets_.pop(); - } - - uint32_t nb_frames() const - { - return std::max(nb_frames_, file_frame_number_); - } - - std::wstring print() const - { - return L"[video-decoder] " + u16(codec_context_->codec->long_name); - } -}; - -video_decoder::video_decoder() : impl_(new impl()){} -video_decoder::video_decoder(const spl::shared_ptr& context) : impl_(new impl(context)){} -video_decoder::video_decoder(video_decoder&& other) : impl_(std::move(other.impl_)){} -video_decoder& video_decoder::operator=(video_decoder&& other){impl_ = std::move(other.impl_); return *this;} -void video_decoder::push(const std::shared_ptr& packet){impl_->push(packet);} -std::shared_ptr video_decoder::poll(){return impl_->poll();} -bool video_decoder::ready() const{return impl_->ready();} -int video_decoder::width() const{return impl_->width_;} -int video_decoder::height() const{return impl_->height_;} -uint32_t video_decoder::nb_frames() const{return impl_->nb_frames();} -uint32_t video_decoder::file_frame_number() const{return impl_->file_frame_number_;} -bool video_decoder::is_progressive() const{return impl_->is_progressive_;} -std::wstring video_decoder::print() const{return impl_->print();} -void video_decoder::clear(){impl_->clear();} -void video_decoder::subscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.subscribe(o);} -void video_decoder::unsubscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.unsubscribe(o);} - -}} \ No newline at end of file +/* +* Copyright (c) 2011 Sveriges Television AB +* +* This file is part of CasparCG (www.casparcg.com). +* +* CasparCG is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* CasparCG is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with CasparCG. If not, see . +* +* Author: Robert Nagy, ronag89@gmail.com +*/ + +#include "../../StdAfx.h" + +#include "video_decoder.h" + +#include "../util/util.h" +#include "../input/input.h" + +#include "../../ffmpeg_error.h" + +#include +#include +#include + +#include + +#include + +#include + +#if defined(_MSC_VER) +#pragma warning (push) +#pragma warning (disable : 4244) +#endif +extern "C" +{ + #include + #include +} +#if defined(_MSC_VER) +#pragma warning (pop) +#endif + +namespace caspar { namespace ffmpeg { + +struct video_decoder::impl : boost::noncopyable +{ + core::monitor::subject monitor_subject_; + input* input_; + int index_ = -1; + const spl::shared_ptr codec_context_; + + std::queue> packets_; + + const AVStream* stream_; + const uint32_t nb_frames_; + const int width_; + const int height_; + + tbb::atomic is_progressive_; + tbb::atomic file_frame_number_; + boost::rational framerate_; + + std::shared_ptr current_packet_; + +public: + explicit impl(input& in, bool single_threaded) + : input_(&in) + , codec_context_(open_codec(input_->context(), AVMEDIA_TYPE_VIDEO, index_, single_threaded)) + , stream_(input_->context().streams[index_]) + , nb_frames_(static_cast(stream_->nb_frames)) + , width_(codec_context_->width) + , height_(codec_context_->height) + , framerate_(read_framerate(input_->context(), 0)) + { + is_progressive_ = false; + file_frame_number_ = 0; + } + + std::shared_ptr poll() + { + if(!current_packet_ && !input_->try_pop_video(current_packet_)) + return nullptr; + + std::shared_ptr frame; + + if (!current_packet_->data) + { + if(codec_context_->codec->capabilities & CODEC_CAP_DELAY) + frame = decode(*current_packet_); + + if (!frame) + { + file_frame_number_ = static_cast(current_packet_->pos); + avcodec_flush_buffers(codec_context_.get()); + current_packet_.reset(); + frame = flush(); + } + } + else + { + frame = decode(*current_packet_); + + if(current_packet_->size == 0) + current_packet_.reset(); + } + + return frame; + } + + std::shared_ptr decode(AVPacket& pkt) + { + auto frame = create_frame(); + + int got_frame = 0; + auto len = THROW_ON_ERROR2(avcodec_decode_video2(codec_context_.get(), frame.get(), &got_frame, &pkt), "[video_decocer]"); + + if(len == 0) + { + pkt.size = 0; + return nullptr; + } + + pkt.data += len; + pkt.size -= len; + + if(got_frame == 0) + return nullptr; + + ++file_frame_number_; + + is_progressive_ = !frame->interlaced_frame; + + if(frame->repeat_pict > 0) + CASPAR_LOG(warning) << "[video_decoder] repeat_pict not implemented."; + + monitor_subject_ << core::monitor::message("/file/video/width") % width_ + << core::monitor::message("/file/video/height") % height_ + << core::monitor::message("/file/video/field") % u8(!frame->interlaced_frame ? "progressive" : (frame->top_field_first ? "upper" : "lower")) + << core::monitor::message("/file/video/codec") % u8(codec_context_->codec->long_name); + + return frame; + } + + uint32_t nb_frames() const + { + return std::max(nb_frames_, static_cast(file_frame_number_)); + } + + std::wstring print() const + { + return L"[video-decoder] " + u16(codec_context_->codec->long_name); + } +}; + +video_decoder::video_decoder(input& in, bool single_threaded) : impl_(new impl(in, single_threaded)){} +video_decoder::video_decoder(video_decoder&& other) : impl_(std::move(other.impl_)){} +video_decoder& video_decoder::operator=(video_decoder&& other){impl_ = std::move(other.impl_); return *this;} +std::shared_ptr video_decoder::operator()(){return impl_->poll();} +int video_decoder::width() const{return impl_->width_;} +int video_decoder::height() const{return impl_->height_;} +uint32_t video_decoder::nb_frames() const{return impl_->nb_frames();} +uint32_t video_decoder::file_frame_number() const{return impl_->file_frame_number_;} +boost::rational video_decoder::framerate() const { return impl_->framerate_; } +bool video_decoder::is_progressive() const{return impl_->is_progressive_;} +std::wstring video_decoder::print() const{return impl_->print();} +core::monitor::subject& video_decoder::monitor_output() { return impl_->monitor_subject_; } +}}