X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fffmpeg%2Fproducer%2Fvideo%2Fvideo_decoder.cpp;h=9322baad4ba1db6a67669e8df3c184ace5eaef85;hb=dd0fc2703b330461b26e0a2935d72a5fcf3970c0;hp=5d94f21690f80b39ecf30c208ec4ba0694bc8ab0;hpb=28d3e7c5efbf12eb494650aeb31d1a379befff21;p=casparcg diff --git a/modules/ffmpeg/producer/video/video_decoder.cpp b/modules/ffmpeg/producer/video/video_decoder.cpp index 5d94f2169..9322baad4 100644 --- a/modules/ffmpeg/producer/video/video_decoder.cpp +++ b/modules/ffmpeg/producer/video/video_decoder.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2011 Sveriges Television AB +* Copyright 2013 Sveriges Television AB http://casparcg.com/ * * This file is part of CasparCG (www.casparcg.com). * @@ -19,16 +19,14 @@ * Author: Robert Nagy, ronag89@gmail.com */ -#include "../../stdafx.h" +#include "../../StdAfx.h" #include "video_decoder.h" #include "../util/util.h" -#include "../input/input.h" #include "../../ffmpeg_error.h" -#include #include #include @@ -41,7 +39,7 @@ #pragma warning (push) #pragma warning (disable : 4244) #endif -extern "C" +extern "C" { #include #include @@ -51,127 +49,125 @@ extern "C" #endif namespace caspar { namespace ffmpeg { - -struct video_decoder::impl : boost::noncopyable + +struct video_decoder::implementation : boost::noncopyable { - monitor::subject monitor_subject_; - input* input_; - int index_; + 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_; + const int width_ = codec_context_->width; + const int height_ = codec_context_->height; bool is_progressive_; - uint32_t file_frame_number_; - double fps_; - - std::shared_ptr current_packet_; + + tbb::atomic file_frame_number_; public: - explicit impl(input& in) - : input_(&in) - , codec_context_(open_codec(input_->context(), AVMEDIA_TYPE_VIDEO, index_)) - , stream_(input_->context().streams[index_]) - , nb_frames_(static_cast(stream_->nb_frames)) - , width_(codec_context_->width) - , height_(codec_context_->height) - , file_frame_number_(0) - , fps_(read_fps(input_->context(), 0.0)) + 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(!current_packet_ && !input_->try_pop_video(current_packet_)) + { + if(packets_.empty()) return nullptr; - - std::shared_ptr frame; - if(!current_packet_) - { - avcodec_flush_buffers(codec_context_.get()); - } - else if(!current_packet_->data) - { - if(codec_context_->codec->capabilities & CODEC_CAP_DELAY) - frame = decode(*current_packet_); - - if(!frame) - current_packet_.reset(); - } - else + auto packet = packets_.front(); + + if(packet->data == nullptr) { - frame = decode(*current_packet_); - - if(current_packet_->size == 0) - current_packet_.reset(); + if(codec_context_->codec->capabilities & CODEC_CAP_DELAY) + { + auto video = decode(packet); + if(video) + return video; + } + + packets_.pop(); + + if (packet->pos != -1) + { + file_frame_number_ = static_cast(packet->pos); + avcodec_flush_buffers(codec_context_.get()); + return flush_video(); + } + else // Really EOF + return nullptr; } - - return frame ? frame : poll(); + + packets_.pop(); + return decode(packet); } - std::shared_ptr decode(AVPacket& pkt) + std::shared_ptr decode(spl::shared_ptr pkt) { - auto frame = create_frame(); + auto decoded_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; - } + int frame_finished = 0; + THROW_ON_ERROR2(avcodec_decode_video2(codec_context_.get(), decoded_frame.get(), &frame_finished, pkt.get()), "[video_decoder]"); - pkt.data += len; - pkt.size -= len; + // 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(got_frame == 0) + if(frame_finished == 0) return nullptr; - - auto stream_time_base = stream_->time_base; - auto packet_frame_number = static_cast((static_cast(pkt.pts * stream_time_base.num)/stream_time_base.den)*fps_); - - file_frame_number_ = packet_frame_number; - - is_progressive_ = !frame->interlaced_frame; - - if(frame->repeat_pict > 0) - CASPAR_LOG(warning) << "[video_decoder] repeat_pict not implemented."; - - monitor_subject_ << monitor::message("/file/video/width") % width_ - << monitor::message("/file/video/height") % height_ - << monitor::message("/file/video/field") % u8(!frame->interlaced_frame ? "progressive" : (frame->top_field_first ? "upper" : "lower")) - << monitor::message("/file/video/codec") % u8(codec_context_->codec->long_name); - - return frame; + + 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_, file_frame_number_); + 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) : impl_(new impl(in)){} -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();} +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 impl_->file_frame_number_;} -bool video_decoder::is_progressive() const{return impl_->is_progressive_;} +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();} -monitor::source& video_decoder::monitor_output() { return impl_->monitor_subject_; } -}} \ No newline at end of file + +}}