X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fffmpeg%2Fproducer%2Fvideo%2Fvideo_decoder.cpp;h=10d7aee98829a6886b0b4055de5f544ab40554f0;hb=b8c8660af595b9897af41183fe8b12786d45af98;hp=7ee3b833a16070880cc009a99fcdb4e4d75f254c;hpb=ab2707f64f6e8c93023d4a9c14349b780370365f;p=casparcg diff --git a/modules/ffmpeg/producer/video/video_decoder.cpp b/modules/ffmpeg/producer/video/video_decoder.cpp index 7ee3b833a..10d7aee98 100644 --- a/modules/ffmpeg/producer/video/video_decoder.cpp +++ b/modules/ffmpeg/producer/video/video_decoder.cpp @@ -1,173 +1,167 @@ -/* -* 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::subject event_subject_; - int index_; - const spl::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(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(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 packets_.size() >= 8; - } - - 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(const spl::shared_ptr& context) : impl_(new impl(context)){} -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::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 2013 Sveriges Television AB http://casparcg.com/ +* +* 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 + +#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::implementation : boost::noncopyable +{ + int index_ = -1; + const spl::shared_ptr codec_context_; + + std::queue> packets_; + + const uint32_t nb_frames_; + + const int width_ = codec_context_->width; + const int height_ = codec_context_->height; + bool is_progressive_; + + tbb::atomic file_frame_number_; + +public: + explicit implementation(const spl::shared_ptr& context) + : codec_context_(open_codec(*context, AVMEDIA_TYPE_VIDEO, index_, false)) + , nb_frames_(static_cast(context->streams[index_]->nb_frames)) + { + file_frame_number_ = 0; + + codec_context_->refcounted_frames = 1; + } + + 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(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(spl::shared_ptr pkt) + { + auto decoded_frame = create_frame(); + + int frame_finished = 0; + THROW_ON_ERROR2(avcodec_decode_video2(codec_context_.get(), decoded_frame.get(), &frame_finished, pkt.get()), "[video_decoder]"); + + // 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."; + + ++file_frame_number_; + + // This ties the life of the decoded_frame to the packet that it came from. For the + // current version of ffmpeg (0.8 or c17808c) the RAW_VIDEO codec returns frame data + // owned by the packet. + return std::shared_ptr(decoded_frame.get(), [decoded_frame, pkt](AVFrame*){}); + } + + bool ready() const + { + return packets_.size() >= 8; + } + + 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(const spl::shared_ptr& context) : impl_(new implementation(context)){} +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 static_cast(impl_->file_frame_number_);} +bool video_decoder::is_progressive() const{return impl_->is_progressive_;} +std::wstring video_decoder::print() const{return impl_->print();} + +}}