void VideoFFmpegWriter::finish()
{
	if( _error == IGNORE_FINISH )
		return;
	av_write_trailer( _avformatOptions );
	avcodec_close( _stream->codec );
	if( !( _avformatOptions->oformat->flags & AVFMT_NOFILE ) )
		url_fclose( _avformatOptions->pb );
	freeFormat();
}
int VideoFFmpegWriter::execute( boost::uint8_t* in_buffer, int in_width, int in_height, PixelFormat in_pixelFormat )
{
	_error = IGNORE_FINISH;

	AVOutputFormat* fmt = 0;
	fmt = guess_format( _format.c_str(), NULL, NULL );
	if( !fmt )
	{
		fmt = guess_format( NULL, filename().c_str(), NULL );
		if( !fmt )
		{
			std::cerr << "ffmpegWriter: could not deduce output format from file extension." << std::endl;
			return false;
		}
	}

	if( !_avformatOptions )
		_avformatOptions = avformat_alloc_context();

	_avformatOptions->oformat = fmt;
	snprintf( _avformatOptions->filename, sizeof( _avformatOptions->filename ), "%s", filename().c_str() );

	if( !_stream )
	{
		_stream = av_new_stream( _avformatOptions, 0 );
		if( !_stream )
		{
			std::cout << "ffmpegWriter: out of memory." << std::endl;
			return false;
		}

		CodecID codecId    = fmt->video_codec;
		AVCodec* userCodec = avcodec_find_encoder_by_name( _codec.c_str() );
		if( userCodec )
			codecId = userCodec->id;

		_stream->codec->codec_id           = codecId;
		_stream->codec->codec_type         = CODEC_TYPE_VIDEO;
		_stream->codec->bit_rate           = _bitRate;
		_stream->codec->bit_rate_tolerance = _bitRateTolerance;
		_stream->codec->width              = width();
		_stream->codec->height             = height();
		_stream->codec->time_base          = av_d2q( 1.0 / _fps, 100 );
		_stream->codec->gop_size           = _gopSize;
		if( _bFrames )
		{
			_stream->codec->max_b_frames     = _bFrames;
			_stream->codec->b_frame_strategy = 0;
			_stream->codec->b_quant_factor   = 2.0;
		}
		_stream->codec->mb_decision = _mbDecision;
		_stream->codec->pix_fmt     = _out_pixelFormat;

		if( !strcmp( _avformatOptions->oformat->name, "mp4" ) || !strcmp( _avformatOptions->oformat->name, "mov" ) || !strcmp( _avformatOptions->oformat->name, "3gp" ) || !strcmp( _avformatOptions->oformat->name, "flv" ) )
			_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;

		if( av_set_parameters( _avformatOptions, NULL ) < 0 )
		{
			std::cout << "ffmpegWriter: unable to set parameters." << std::endl;
			freeFormat();
			return false;
		}

		dump_format( _avformatOptions, 0, filename().c_str(), 1 );

		AVCodec* videoCodec = avcodec_find_encoder( codecId );
		if( !videoCodec )
		{
			std::cout << "ffmpegWriter: unable to find codec." << std::endl;
			freeFormat();
			return false;
		}

		if( avcodec_open( _stream->codec, videoCodec ) < 0 )
		{
			std::cout << "ffmpegWriter: unable to open codec." << std::endl;
			freeFormat();
			return false;
		}

		if( !( fmt->flags & AVFMT_NOFILE ) )
		{
			if( url_fopen( &_avformatOptions->pb, filename().c_str(), URL_WRONLY ) < 0 )
			{
				std::cout << "ffmpegWriter: unable to open file." << std::endl;
				return false;
			}
		}

		av_write_header( _avformatOptions );
	}

	_error = CLEANUP;

	AVFrame* in_frame = avcodec_alloc_frame();
	avcodec_get_frame_defaults( in_frame );
	avpicture_fill( (AVPicture*)in_frame, in_buffer, in_pixelFormat, in_width, in_height );

	AVFrame* out_frame = avcodec_alloc_frame();
	avcodec_get_frame_defaults( out_frame );
	int out_picSize            = avpicture_get_size( _out_pixelFormat, width(), height() );
	boost::uint8_t* out_buffer = (boost::uint8_t*) av_malloc( out_picSize );
	avpicture_fill( (AVPicture*) out_frame, out_buffer, _out_pixelFormat, width(), height() );

	_sws_context = sws_getCachedContext( _sws_context, in_width, in_height, in_pixelFormat, width(), height(), _out_pixelFormat, SWS_BICUBIC, NULL, NULL, NULL );

	std::cout << "ffmpegWriter: input format: " << pixelFormat_toString( in_pixelFormat ) << std::endl;
	std::cout << "ffmpegWriter: output format: " << pixelFormat_toString( _out_pixelFormat ) << std::endl;

	if( !_sws_context )
	{
		std::cout << "ffmpeg-conversion failed (" << in_pixelFormat << "->" << _out_pixelFormat << ")." << std::endl;
		return false;
	}
	int error = sws_scale( _sws_context, in_frame->data, in_frame->linesize, 0, height(), out_frame->data, out_frame->linesize );
	if( error < 0 )
	{
		std::cout << "ffmpeg-conversion failed (" << in_pixelFormat << "->" << _out_pixelFormat << ")." << std::endl;
		return false;
	}

	int ret = 0;
	if( ( _avformatOptions->oformat->flags & AVFMT_RAWPICTURE ) != 0 )
	{
		AVPacket pkt;
		av_init_packet( &pkt );
		pkt.flags       |= PKT_FLAG_KEY;
		pkt.stream_index = _stream->index;
		pkt.data         = (boost::uint8_t*) out_frame;
		pkt.size         = sizeof( AVPicture );
		ret              = av_interleaved_write_frame( _avformatOptions, &pkt );
	}
	else
	{
		boost::uint8_t* out_buffer = (boost::uint8_t*) av_malloc( out_picSize );

		ret = avcodec_encode_video( _stream->codec, out_buffer, out_picSize, out_frame );

		if( ret > 0 )
		{
			AVPacket pkt;
			av_init_packet( &pkt );

			if( _stream->codec->coded_frame && _stream->codec->coded_frame->pts != static_cast<boost::int64_t>( AV_NOPTS_VALUE ) ) // static_cast<unsigned long> (
				pkt.pts = av_rescale_q( _stream->codec->coded_frame->pts, _stream->codec->time_base, _stream->time_base );

			if( _stream->codec->coded_frame && _stream->codec->coded_frame->key_frame )
				pkt.flags |= PKT_FLAG_KEY;

			pkt.stream_index = _stream->index;
			pkt.data         = out_buffer;
			pkt.size         = ret;
			ret              = av_interleaved_write_frame( _avformatOptions, &pkt );
		}

		av_free( out_buffer );
	}

	av_free( out_buffer );
	av_free( out_frame );
	av_free( in_frame );
	// in_buffer not free (function parameter)

	if( ret )
	{
		std::cout << "ffmpegWriter: error writing frame to file." << std::endl;
		return false;
	}

	_error = SUCCESS;
	return true;
}
Example #3
0
int VideoFFmpegWriter::execute( boost::uint8_t* in_buffer, int in_width, int in_height, PixelFormat in_pixelFormat )
{
	_error = IGNORE_FINISH;

	if( !_avformatOptions )
	{
		// TODO avformat_alloc_context2 can guess format from filename
		// if format name is NULL, find a way to expose the feature
		if (avformat_alloc_output_context2(&_avformatOptions, NULL, _formatName.c_str(), filename().c_str()) < 0)
		{
			TUTTLE_CERR( "ffmpegWriter: output context allocation failed" );
			return false;
		}
		_ofmt = _avformatOptions->oformat;
		TUTTLE_CERR( "ffmpegWriter: " << std::string(_ofmt->name) << " format selected" );
	}

	if( !_stream )
	{
		_codec = avcodec_find_encoder_by_name( _codecName.c_str() );
		if (!_codec)
		{
			TUTTLE_CERR( "ffmpegWriter: codec not found" );
			return false;
		}
		TUTTLE_CERR( "ffmpegWriter: " << std::string(_codec->name) << " codec selected" );

		_stream = avformat_new_stream( _avformatOptions, _codec );
		if( !_stream )
		{
			TUTTLE_CERR( "ffmpegWriter: out of memory." );
			return false;
		}
		avcodec_get_context_defaults3(_stream->codec, _codec);

		if( _videoPresetName.length() !=0 )
		{
			TUTTLE_COUT( "ffmpegWriter: " << _videoPresetName << " preset selected" );
			std::string presetFilename = getFilename( std::string(_codec->name), _videoPresetName );
			
			PresetsOptions opts = getOptionsForPresetFilename( presetFilename );
			PresetsOptions::iterator itOpt;
			for ( itOpt = opts.begin() ; itOpt != opts.end(); itOpt++ )
			{
				int ret = av_opt_set( (void*)_stream->codec, (*itOpt).first.c_str(), (*itOpt).second.c_str(), 0);
				switch( ret )
				{
					case AVERROR_OPTION_NOT_FOUND: TUTTLE_CERR( "ffmpegPreset: unable to find " << (*itOpt).first ); break;
					case AVERROR(EINVAL): TUTTLE_CERR( "ffmpegPreset: invalid value " << (*itOpt).second.c_str() << " for option " << (*itOpt).first ); break;
					case AVERROR(ERANGE): TUTTLE_CERR( "ffmpegPreset: invalid range for parameter " << (*itOpt).first << " : " << (*itOpt).second.c_str() ); break;
				}
			}
		}
		
		_stream->codec->bit_rate           = _bitRate;
		_stream->codec->bit_rate_tolerance = _bitRateTolerance;
		_stream->codec->width              = width();
		_stream->codec->height             = height();
		_stream->codec->time_base          = av_d2q( 1.0 / _fps, 100 );
		_stream->codec->gop_size           = _gopSize;
		_stream->codec->sample_rate        = 48000; ///< samples per second
		_stream->codec->channels           = 0;     ///< number of audio channels
		if( _bFrames )
		{
			_stream->codec->max_b_frames     = _bFrames;
			_stream->codec->b_frame_strategy = 0;
			_stream->codec->b_quant_factor   = 2.0;
		}
		_stream->codec->mb_decision = _mbDecision;

		int pixfmt_allowed = 0, k;
		if ( _codec->pix_fmts )
		{
			for ( k = 0; _codec->pix_fmts[k] != PIX_FMT_NONE; k++ )
			{
				if ( _codec->pix_fmts[k] == _out_pixelFormat )
				{
					pixfmt_allowed = 1;
					break;
				}
			}
		}
		else
		{
			// If a codec does not contain a list of supported pixel
			// formats, just assume that _out_PixelFormat is valid
			pixfmt_allowed = 1;
		}

		if ( !pixfmt_allowed )
		{
			// av_get_pix_fmt_name requires lavu 51.3.0 or higher
			TUTTLE_CERR( "ffmpegWriter: pixel format " << av_get_pix_fmt_name(_out_pixelFormat) << " not available in codec" );
			_out_pixelFormat = _codec->pix_fmts[0];
			TUTTLE_CERR( "ffmpegWriter: auto-selecting " << av_get_pix_fmt_name(_out_pixelFormat) );
		}
		_stream->codec->pix_fmt     = _out_pixelFormat;

		if( !strcmp( _avformatOptions->oformat->name, "mp4" ) || !strcmp( _avformatOptions->oformat->name, "mov" ) || !strcmp( _avformatOptions->oformat->name, "3gp" ) || !strcmp( _avformatOptions->oformat->name, "flv" ) )
			_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;

		av_dump_format( _avformatOptions, 0, filename().c_str(), 1 );

		if( avcodec_open2( _stream->codec, _codec, NULL ) < 0 )
		{
			TUTTLE_CERR( "ffmpegWriter: unable to open codec." );
			freeFormat();
			return false;
		}

		if( !( _ofmt->flags & AVFMT_NOFILE ) )
		{
			if( avio_open2( &_avformatOptions->pb, filename().c_str(),
                                        AVIO_FLAG_WRITE, NULL, NULL ) < 0 )
			{
				TUTTLE_CERR( "ffmpegWriter: unable to open file." );
				freeFormat();
				return false;
			}
		}

		avformat_write_header( _avformatOptions, NULL );
	}

	_error = CLEANUP;

	AVFrame* in_frame = avcodec_alloc_frame();
	avcodec_get_frame_defaults( in_frame );
	avpicture_fill( (AVPicture*)in_frame, in_buffer, in_pixelFormat, in_width, in_height );

	AVFrame* out_frame = avcodec_alloc_frame();
	avcodec_get_frame_defaults( out_frame );
	int out_picSize            = avpicture_get_size( _out_pixelFormat, width(), height() );
	boost::uint8_t* out_buffer = (boost::uint8_t*) av_malloc( out_picSize );
	avpicture_fill( (AVPicture*) out_frame, out_buffer, _out_pixelFormat, width(), height() );

	_sws_context = sws_getCachedContext( _sws_context, in_width, in_height, in_pixelFormat, width(), height(), _out_pixelFormat, SWS_BICUBIC, NULL, NULL, NULL );

	TUTTLE_COUT( "ffmpegWriter: input format: " << av_get_pix_fmt_name( in_pixelFormat ) );
	TUTTLE_COUT( "ffmpegWriter: output format: " << av_get_pix_fmt_name( _out_pixelFormat ) );

	if( !_sws_context )
	{
		TUTTLE_CERR( "ffmpeg-conversion failed (" << in_pixelFormat << "->" << _out_pixelFormat << ")." );
		return false;
	}
	int error = sws_scale( _sws_context, in_frame->data, in_frame->linesize, 0, height(), out_frame->data, out_frame->linesize );
	if( error < 0 )
	{
		TUTTLE_CERR( "ffmpeg-conversion failed (" << in_pixelFormat << "->" << _out_pixelFormat << ")." );
		return false;
	}

	int ret = 0;
	if( ( _avformatOptions->oformat->flags & AVFMT_RAWPICTURE ) != 0 )
	{
		AVPacket pkt;
		av_init_packet( &pkt );
		pkt.flags       |= AV_PKT_FLAG_KEY;
		pkt.stream_index = _stream->index;
		pkt.data         = (boost::uint8_t*) out_frame;
		pkt.size         = sizeof( AVPicture );
		ret              = av_interleaved_write_frame( _avformatOptions, &pkt );
	}
	else
	{
		AVPacket pkt;
		int hasFrame = 0;
		av_init_packet( &pkt );
		pkt.size = 0;
		pkt.data = NULL;
		pkt.stream_index = _stream->index;

		if( _stream->codec->coded_frame && _stream->codec->coded_frame->pts != static_cast<boost::int64_t>( AV_NOPTS_VALUE ) ) // static_cast<unsigned long> (
			pkt.pts = av_rescale_q( _stream->codec->coded_frame->pts, _stream->codec->time_base, _stream->time_base );

		if( _stream->codec->coded_frame && _stream->codec->coded_frame->key_frame )
			pkt.flags |= AV_PKT_FLAG_KEY;

		out_frame->pts = pts++;
		ret = avcodec_encode_video2( _stream->codec, &pkt, out_frame,  &hasFrame );
		if ( ret < 0 )
			return false;

		if ( hasFrame )
		{
			ret = av_interleaved_write_frame( _avformatOptions, &pkt );
			if ( ret < 0 )
			{
				TUTTLE_CERR( "ffmpegWriter: error writing packet to file" );
				return false;
			}
		}
	}

	av_free( out_buffer );
	av_free( out_frame );
	av_free( in_frame );
	// in_buffer not free (function parameter)

	if( ret )
	{
		TUTTLE_CERR( "ffmpegWriter: error writing frame to file." );
		return false;
	}

	_error = SUCCESS;
	return true;
}
Example #4
0
int main(void)
{
	struct pollfd sfd[3];
	const long timeout=500; //connection timeout in seconds

	struct timespec ts_timeout;

	int size;

	field *pmessage;

	fldformat *frm;

	isomessage smessage;

	GOOGLE_PROTOBUF_VERIFY_VERSION;

	frm=loadNetFormat();

	if(!frm)
	{
		printf("Error: Can't load format\n");
		return 1;
	}

	printf("Message format loaded\n");

	sfd[2].fd=tcpinit();

	if(sfd[2].fd==-1)
	{
		printf("Error: Unable to start TCP connection\n");
		freeFormat(frm);
		return 1;
	}

	sfd[0].fd=ipcopen((char *)"visa");

	if(sfd[0].fd==-1)
	{
		printf("Error: Unable to connect to switch\n");
		close(sfd[2].fd);
		freeFormat(frm);
		return 1;
	}

	if (signal(SIGINT, catch_sigint) == SIG_ERR)
		printf("Warning: unable to set the signal handler\n");

	sfd[0].events=POLLIN;
	sfd[1].events=POLLIN;

	while (1)
	{
		printf("Waiting for a connection...\n");

		errno=0;
		sfd[1].fd=tcpconnect(sfd[2].fd);
		if(sfd[1].fd==-1)
		{
			if(sigint_caught)
			{
				printf("onnection aborted^\n");
				break;
			}

			printf("Connection error: %s\n", strerror(errno));
			sleep(1);
			continue;
		}

		printf("Connected.\n");

		while (1)
		{
			printf("Waiting for a message...\n");

			ts_timeout.tv_sec=timeout;
			ts_timeout.tv_nsec=0;
			errno=0;

			size=ppoll(sfd, 2, &ts_timeout, NULL);

			//printf("poll: %d: %hd, %hd: %s\n", size, sfd[0].revents, sfd[1].revents, strerror(errno));

			if(size==-1)
			{
				if(sigint_caught)
				{
					printf("losing connection^\n");
					break;
				}

				printf("Error: poll (%hd, %hd): %s\n", sfd[0].revents, sfd[1].revents, strerror(errno));
				if(sfd[1].revents)
					break;
				else
				{
					usleep(100000);
					continue;
				}
			}
			else if(size==0)
			{
				printf("Error: Connection is inactive, closing it %ld, %ld\n", ts_timeout.tv_sec, ts_timeout. tv_nsec);
				break;
			}

			if(sfd[1].revents & POLLIN)
			{
				printf("Receiving message from net\n");

				size=tcprecvmsg(sfd[1].fd, &pmessage, frm);

				if(size==-1)
				{
					printf("Closing connection\n");
					break;
				}
				else if(size==0)
					continue;

				print_message(pmessage);

				if(isNetMgmt(pmessage))
				{
					if(isNetRequest(pmessage))
					{
						if(!processNetMgmt(pmessage))
						{
							printf("Error: Unable to process Network Management request. Message dropped.\n");
							freeField(pmessage);
							continue;
						}

						print_message(pmessage);

						size=tcpsendmsg(sfd[1].fd, pmessage);

						if(size==-1)
						{
							printf("Closing connection\n");
							freeField(pmessage);
							break;
						}
						else if(size==0)
						{
							freeField(pmessage);
							continue;
						}

						printf("Network Management Message sent (%d bytes)\n", size);
					}

					freeField(pmessage);
					continue;
				}

				if(translateNetToSwitch(&smessage, pmessage)!=0)
				{
					printf("Error: Unable to translate the message to format-independent representation.\n");

					if(isNetRequest(pmessage))
					{
						if(!declineNetMsg(pmessage))
						{
							printf("Error: Unable to decline the request. Message dropped.\n");
							freeField(pmessage);
							continue;
						}

						print_message(pmessage);

						size=tcpsendmsg(sfd[1].fd, pmessage);

						if(size==-1)
						{
							printf("Closing connection\n");
							freeField(pmessage);
							break;
						}
						else if(size==0)
						{
							freeField(pmessage);
							continue;
						}

						printf("Decline message sent (%d bytes)\n", size);
					}

					freeField(pmessage);
					continue;
				}

				printf("Converted message:\n");
				smessage.PrintDebugString();

				size=ipcsendmsg(sfd[0].fd, &smessage, (char *)"switch");

				if(size<=0)
				{
					printf("Error: Unable to send the message to switch\n");

					if(isNetRequest(pmessage))
					{
						if(!declineNetMsg(pmessage))
						{
							printf("Error: Unable to decline the request. Message dropped.\n");
							freeField(pmessage);
							continue;
						}

						print_message(pmessage);

						size=tcpsendmsg(sfd[1].fd, pmessage);

						if(size==-1)
						{
							printf("Closing connection\n");
							freeField(pmessage);
							break;
						}
						else if(size==0)
						{
							freeField(pmessage);
							continue;
						}

						printf("Decline message sent (%d bytes)\n", size);
					}

					freeField(pmessage);
					continue;
				}

				freeField(pmessage);

				printf("Message sent, size is %d bytes.\n", size);
			}

			if(sfd[0].revents & POLLIN)
			{
				printf("Receiving message from switch\n");

				if(ipcrecvmsg(sfd[0].fd, &smessage)<0)
					continue;

				printf("\nOutgoingMessage:\n");
		                smessage.PrintDebugString();

				pmessage=translateSwitchToNet(&smessage, frm);

				if(!pmessage)
				{
					printf("Error: Unable to translate the message from format-independent representation.\n");

					if(isRequest(&smessage))
					{
						if(!declineMsg(&smessage))
						{
							printf("Error: Unable to decline the request. Message dropped.\n");
							continue;
						}

						smessage.PrintDebugString();

						size=ipcsendmsg(sfd[0].fd, &smessage, (char *)"switch");

						if(size<=0)
						{
							printf("Error: Unable to return the declined message to switch. Message dropped.\n");
							continue;
						}

						printf("Decline message sent (%d bytes)\n", size);

					}
					continue;
				}

				print_message(pmessage);

				size=tcpsendmsg(sfd[1].fd, pmessage);

				freeField(pmessage);

				if(size==-1)
				{
					printf("Closing connection\n");

					if(isRequest(&smessage))
					{
						if(!declineMsg(&smessage))
						{
							printf("Error: Unable to decline the request. Message dropped.\n");
							continue;
						}

						smessage.PrintDebugString();

						size=ipcsendmsg(sfd[0].fd, &smessage, (char *)"switch");

						if(size<=0)
						{
							printf("Error: Unable to return the declined message to switch. Message dropped.\n");
							continue;
						}

						printf("Decline message sent (%d bytes)\n", size);

					}
					break;
				}
				else if(size==0)
				{
					if(isRequest(&smessage))
					{
						if(!declineMsg(&smessage))
						{
							printf("Error: Unable to decline the request. Message dropped.\n");
							continue;
						}

						smessage.PrintDebugString();

						size=ipcsendmsg(sfd[0].fd, &smessage, (char *)"switch");

						if(size<=0)
						{
							printf("Error: Unable to return the declined message to switch. Message dropped.\n");
							continue;
						}

						printf("Decline message sent (%d bytes)\n", size);
					}
					continue;
				}

				printf("Message sent (%d bytes)\n", size);
			}

		}

		tcpclose(sfd[1].fd);

		printf("Disconnected.\n");

		if(sigint_caught)
			break;
	}

	tcpclose(sfd[2].fd);
	ipcclose(sfd[0].fd);
	freeFormat(frm);
	google::protobuf::ShutdownProtobufLibrary();
	
	return 0;
}