Exemple #1
0
	std::shared_ptr<AVFrame> decode(safe_ptr<AVPacket> pkt)
	{
		std::shared_ptr<AVFrame> 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.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<AVFrame>(decoded_frame.get(), [decoded_frame, pkt](AVFrame*){});
	}
Exemple #2
0
	std::shared_ptr<AVStream> add_audio_stream(std::vector<option>& options)
	{
		if(output_format_.acodec == CODEC_ID_NONE)
			return nullptr;

		auto st = av_new_stream(oc_.get(), 1);
		if(!st)
			BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Could not allocate audio-stream") << boost::errinfo_api_function("av_new_stream"));		
		
		auto encoder = avcodec_find_encoder(output_format_.acodec);
		if (!encoder)
			BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("codec not found"));
		
		auto c = st->codec;

		avcodec_get_context_defaults3(c, encoder);

		c->codec_id			= output_format_.acodec;
		c->codec_type		= AVMEDIA_TYPE_AUDIO;
		c->sample_rate		= 48000;
		c->channels			= channel_layout_.num_channels;
		c->sample_fmt		= SAMPLE_FMT_S16;

		if(output_format_.vcodec == CODEC_ID_FLV1)		
			c->sample_rate	= 44100;		

		if(output_format_.format->flags & AVFMT_GLOBALHEADER)
			c->flags |= CODEC_FLAG_GLOBAL_HEADER;
				
		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;
		});

		THROW_ON_ERROR2(avcodec_open(c, encoder), "[ffmpeg_consumer]");

		return std::shared_ptr<AVStream>(st, [](AVStream* st)
		{
			LOG_ON_ERROR2(avcodec_close(st->codec), "[ffmpeg_consumer]");;
			av_freep(&st->codec);
			av_freep(&st);
		});
	}
Exemple #3
0
	void encode_video_frame(core::read_frame& frame)
	{ 
		auto c = video_st_->codec;
		
		auto in_time  = static_cast<double>(in_frame_number_) / format_desc_.fps;
		auto out_time = static_cast<double>(out_frame_number_) / (static_cast<double>(c->time_base.den) / static_cast<double>(c->time_base.num));
		
		in_frame_number_++;

		if(out_time - in_time > 0.01)
			return;
 
		auto av_frame = convert_video(frame, c);
		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;
		av_frame->pts				= out_frame_number_++;

		int out_size = THROW_ON_ERROR2(avcodec_encode_video(c, video_outbuf_.data(), video_outbuf_.size(), av_frame.get()), "[ffmpeg_consumer]");
		if(out_size == 0)
			return;
				
		safe_ptr<AVPacket> pkt(new AVPacket, [](AVPacket* p)
		{
			av_free_packet(p);
			delete p;
		});
		av_init_packet(pkt.get());
 
		if (c->coded_frame->pts != AV_NOPTS_VALUE)
			pkt->pts = av_rescale_q(c->coded_frame->pts, c->time_base, video_st_->time_base);

		if(c->coded_frame->key_frame)
			pkt->flags |= AV_PKT_FLAG_KEY;

		pkt->stream_index	= video_st_->index;
		pkt->data			= video_outbuf_.data();
		pkt->size			= out_size;
 			
		av_interleaved_write_frame(oc_.get(), pkt.get());		
	}
Exemple #4
0
	std::shared_ptr<AVStream> add_video_stream(std::vector<option>& options)
	{ 
		if(output_format_.vcodec == CODEC_ID_NONE)
			return nullptr;

		auto st = av_new_stream(oc_.get(), 0);
		if (!st) 		
			BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Could not allocate video-stream.") << boost::errinfo_api_function("av_new_stream"));		

		auto encoder = avcodec_find_encoder(output_format_.vcodec);
		if (!encoder)
			BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Codec not found."));

		auto c = st->codec;

		avcodec_get_context_defaults3(c, encoder);
				
		c->codec_id			= output_format_.vcodec;
		c->codec_type		= AVMEDIA_TYPE_VIDEO;
		c->width			= output_format_.width;
		c->height			= output_format_.height;
		c->time_base.den	= format_desc_.time_scale;
		c->time_base.num	= format_desc_.duration;
		c->gop_size			= 25;
		c->flags		   |= format_desc_.field_mode == core::field_mode::progressive ? 0 : (CODEC_FLAG_INTERLACED_ME | CODEC_FLAG_INTERLACED_DCT);
		if(c->pix_fmt == PIX_FMT_NONE)
			c->pix_fmt = PIX_FMT_YUV420P;

		if(c->codec_id == CODEC_ID_PRORES)
		{			
			c->bit_rate	= c->width < 1280 ? 63*1000000 : 220*1000000;
			c->pix_fmt	= PIX_FMT_YUV422P10;
		}
		else if(c->codec_id == CODEC_ID_DNXHD)
		{
			if(c->width < 1280 || c->height < 720)
				BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Unsupported video dimensions."));

			c->bit_rate	= 220*1000000;
			c->pix_fmt	= PIX_FMT_YUV422P;
		}
		else if(c->codec_id == CODEC_ID_DVVIDEO)
		{
			c->width = c->height == 1280 ? 960  : c->width;
			
			if(format_desc_.format == core::video_format::ntsc)
				c->pix_fmt = PIX_FMT_YUV411P;
			else if(format_desc_.format == core::video_format::pal)
				c->pix_fmt = PIX_FMT_YUV420P;
			else // dv50
				c->pix_fmt = PIX_FMT_YUV422P;
			
			if(format_desc_.duration == 1001)			
				c->width = c->height == 1080 ? 1280 : c->width;			
			else
				c->width = c->height == 1080 ? 1440 : c->width;			
		}
		else if(c->codec_id == CODEC_ID_H264)
		{			   
			c->pix_fmt = PIX_FMT_YUV420P;    
			if(options.empty())
			{
				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);
			}
		}
		else if(c->codec_id == CODEC_ID_QTRLE)
		{
			c->pix_fmt = PIX_FMT_ARGB;
		}
				
		c->max_b_frames = 0; // b-frames not supported.
				
		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 ||
				   ffmpeg::av_opt_set(c->priv_data, o.name.c_str(), o.value.c_str(), AV_OPT_SEARCH_CHILDREN) > -1;
		});
				
		if(output_format_.format->flags & AVFMT_GLOBALHEADER)
			c->flags |= CODEC_FLAG_GLOBAL_HEADER;
		
		c->thread_count = boost::thread::hardware_concurrency();
		if(avcodec_open(c, encoder) < 0)
		{
			c->thread_count = 1;
			THROW_ON_ERROR2(avcodec_open(c, encoder), "[ffmpeg_consumer]");
		}

		return std::shared_ptr<AVStream>(st, [](AVStream* st)
		{
			LOG_ON_ERROR2(avcodec_close(st->codec), "[ffmpeg_consumer]");
			av_freep(&st->codec);
			av_freep(&st);
		});
	}