LINUX.ORG.RU

Сообщения ryvkin-sergey

 

Нужна помощь по работе с socket`ами (UDP+BROADCAST)

Пишу DHCP-сервер (в академических целях) и вот назрел вопрос. Суть идеи: есть хост с кучей сетевых интерфейсов. На каждый интерфейс можно назначить свои настройки сети, либо не назначать (игнорировать запросы с этих интерфейсов). Я предполагал bind`ить socket на INADDR_ANY и слушать запросы, то есть получаю DHCPDISCOVER или DHCPREQUEST с адреса-источника 0.0.0.0 на адрес-назначение 255.255.255.255 . Так вот, есть ли возможность по recvfrom достать данные об интерфейсе на который пришел udp пакет, или придется под каждый интерфейс bind`ить socket?

 , , ,

ryvkin-sergey
()

Си AVFrame + sws_scale + (видимо кривые руки) = segfault

Доброго времени суток, товарищи. Я столкнулся с проблемой, которую, видимо из-за отсутствия опыта и рук заточенных под си, не могу решить. Пишу программный видеорегистратор. На данном этапе состоит из заголовочного файла libav-dvr-monitor.h :

/* 
 * File:   libav-dvr-monitor.h
 * Author: ryvkin
 *
 * Created on 3 Сентябрь 2013 г., 23:11
 */

#ifndef LIBAV_DVR_MONITOR_H
#define	LIBAV_DVR_MONITOR_H

#ifdef	__cplusplus
extern "C" {
#endif
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libswscale/swscale.h>
#include <stdlib.h>
#include <stdbool.h>
	typedef struct DVRMonitorConnectionStruct{
		bool status;
		AVFormatContext * formatContext;
		int videoStreamOffset;
		struct AVCodecContext * codecContext;
		AVCodec * codec;
		struct SwsContext * swsContext;
		size_t bufferSize;
		u_int8_t * buffer;
	}DVRMonitorConnection;
	typedef struct DVRMonitorStruct{
		int id;
		char * dataSourceName;
		AVDictionary * options;
		DVRMonitorConnection * connection;
		AVFrame * lastFrame;
		AVFrame * lastRGBFrame;
	}DVRMonitor;
	
	DVRMonitor * dvrMonitorAllocte(){
		DVRMonitor * monitor=(DVRMonitor *) malloc(sizeof(DVRMonitor));
		monitor->id=0;
		monitor->dataSourceName=(char *) malloc(sizeof("rtsp://89.222.248.121/av0_1"));
		monitor->dataSourceName="rtsp://89.222.248.121/av0_0";
		printf("Trying to open datasource \"%s\" for monitor with id %i\n", monitor->dataSourceName, monitor->id);
		monitor->options=NULL;
		av_dict_set(&monitor->options, "rtsp_transport", "tcp", 0);
		monitor->connection=(DVRMonitorConnection *) malloc(sizeof(DVRMonitorConnection));
		monitor->connection->status=false;
		monitor->connection->videoStreamOffset=-1;
		monitor->connection->formatContext=NULL;
		monitor->connection->codecContext=NULL;
		monitor->connection->codec=NULL;
		monitor->connection->swsContext=NULL;
		monitor->connection->bufferSize=0;
		monitor->connection->buffer=NULL;
		return monitor;
	}
	bool dvrMonitorOpen(DVRMonitor * monitor){
		av_register_all();
		avformat_network_init();
		monitor->connection->formatContext=avformat_alloc_context();
		printf("Trying to open datasource \"%s\" for monitor with id %i\n", monitor->dataSourceName, monitor->id);
		if(avformat_open_input(&monitor->connection->formatContext, monitor->dataSourceName, NULL, &monitor->options)!=0){
			fprintf(stderr, "Error on monitor with id %i: can't open datasource \"%s\"\n", monitor->id, monitor->dataSourceName);
			return false;
		}
		if(avformat_find_stream_info(monitor->connection->formatContext, &monitor->options)<0){
			fprintf(stderr, "Error on monitor with id %i: can't find stream information for datasource \"%s\"\n", monitor->id, monitor->dataSourceName);
			avformat_close_input(&monitor->connection->formatContext);
		};
		int offset;
		monitor->connection->videoStreamOffset=-1;
		for(offset=0;offset<monitor->connection->formatContext->nb_streams;offset++){
			if(monitor->connection->formatContext->streams[offset]->codec->codec_type==AVMEDIA_TYPE_VIDEO){
				monitor->connection->videoStreamOffset=offset;
				monitor->connection->codecContext=monitor->connection->formatContext->streams[offset]->codec;
				break;
			}
		}
		if(monitor->connection->videoStreamOffset<0){
			fprintf(stderr, "Error on monitor with id %i: video stream was not found in monitor datasource \"%s\"\n", monitor->id, monitor->dataSourceName);
			avformat_close_input(&monitor->connection->formatContext);
			return false;
		}
		monitor->connection->codec=avcodec_find_decoder(monitor->connection->codecContext->codec_id);
		if(monitor->connection->codec==NULL){
			fprintf(stderr, "Error on monitor with id %i: video stream (stream offset: %i) has unsupported codec \"%s\"\n", monitor->id, monitor->connection->videoStreamOffset, monitor->connection->codecContext->codec_name);
			return false;
		}
		if(avcodec_open2(monitor->connection->codecContext, monitor->connection->codec, &monitor->options)<0){
			fprintf(stderr, "Error on monitor with id %i: Can't open codec \"%s\"\n", monitor->id, monitor->connection->codecContext->codec_name);
			return false;
		}
		monitor->lastFrame=avcodec_alloc_frame();
		monitor->lastRGBFrame=avcodec_alloc_frame();
		monitor->connection->bufferSize=
			sizeof(u_int8_t)*
			avpicture_get_size(
				monitor->connection->codecContext->pix_fmt,
				monitor->connection->codecContext->width,
				monitor->connection->codecContext->height
			);
		monitor->connection->buffer=(u_int8_t *) av_malloc(monitor->connection->bufferSize);
		monitor->connection->swsContext=sws_getContext(
			monitor->connection->codecContext->width,
			monitor->connection->codecContext->height,
			monitor->connection->codecContext->pix_fmt,
			monitor->connection->codecContext->width,
			monitor->connection->codecContext->height,
			PIX_FMT_RGBA,
			SWS_BILINEAR,
			NULL,
			NULL,
			NULL
		);
		avpicture_fill(
			(AVPicture *) (monitor->lastRGBFrame),
			monitor->connection->buffer,
			PIX_FMT_RGBA,
			monitor->connection->codecContext->width,
			monitor->connection->codecContext->height
		);
		av_dump_format(monitor->connection->formatContext, 0, monitor->dataSourceName, 0);
		return true;
	}
	bool dvrMonitorReceiveFrame(DVRMonitor * monitor){
		AVPacket packet;
		int frameFinished=0;
		while(av_read_frame(monitor->connection->formatContext, &packet)>=0) {
			if(packet.stream_index==monitor->connection->videoStreamOffset) {
				avcodec_decode_video2(monitor->connection->codecContext, monitor->lastFrame, &frameFinished, &packet);
				if(frameFinished){
					printf("%i\n", frameFinished);
					sws_scale(
						monitor->connection->swsContext,
						(const u_int8_t * const*) monitor->lastFrame->data,
						monitor->lastFrame->linesize,
						0,
						monitor->connection->codecContext->height,
						monitor->lastRGBFrame->data,
						monitor->lastRGBFrame->linesize
					);
					return true;
				}
			}
			av_free_packet(&packet);
		}
		return false;
	}
	void dvrMonitorClose(DVRMonitor * monitor){
		
	}
#ifdef	__cplusplus
}
#endif

#endif	/* LIBAV_DVR_MONITOR_H */
и тестового main-файла main.c :
/* 
 * File:   main.c
 * Author: ryvkin
 *
 * Created on 29 Август 2013 г., 14:34
 */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include "libav-dvr-monitor.h"
/*
 * Константы для задания цвета текста консоли
 */

#define TEXT_COLOR_NORMAL  "\x1B[0m"
#define TEXT_COLOR_RED  "\x1B[31m"
#define TEXT_COLOR_GREEN  "\x1B[32m"
#define TEXT_COLOR_YELOW  "\x1B[33m"
#define TEXT_COLOR_BLUE  "\x1B[34m"
#define TEXT_COLOR_MAGENTA  "\x1B[35m"
#define TEXT_COLOR_CYAN  "\x1B[36m"
#define TEXT_COLOR_WHITE  "\x1B[37m"
/*
 * pid_t daemonize() - функция демонизирует текущий процесс.
 */

pid_t daemonize(){
	pid_t process_id, sid;
	/* Clone ourselves to make a child */  
	process_id = fork(); 
	/* If the pid is less than zero, something went wrong when forking */
	if (process_id < 0) {
		exit(EXIT_FAILURE);
	}
	/* If the pid we got back was greater than zero, then the clone was successful and we are the parent. */
	if (process_id > 0) {
		exit(EXIT_SUCCESS);
	}
	umask(0);
	/* Try to create our own process group */
	sid = setsid();
	if (sid < 0) {
		//syslog(LOG_ERR, "Could not create process group\n");
		fprintf(stderr,  "%sCould not create process group%s\n", TEXT_COLOR_RED, TEXT_COLOR_NORMAL);
		exit(EXIT_FAILURE);
	}
	/* Change the current working directory */
	if ((chdir("/")) < 0) {
		//syslog(LOG_ERR, "Could not change working directory to /\n");
		fprintf(stderr,  "%sCould not change working directory to /%s\n", TEXT_COLOR_RED, TEXT_COLOR_NORMAL);
		exit(EXIT_FAILURE);
	}
	close(STDIN_FILENO);
	close(STDOUT_FILENO);
	close(STDERR_FILENO);
	return getpid();
}

int main(int argc, char** argv) {
	//pid_t process_id=daemonize();

	DVRMonitor * monitor=dvrMonitorAllocte();
	if(dvrMonitorOpen(monitor)){
		printf("Connected\n");
		dvrMonitorReceiveFrame(monitor);
	}else{
		printf(":(\n");
	}
	return (EXIT_SUCCESS);
}
Код написан почти один в один как в tutorial'е (ввиду крайней необходимости объединил все данные используемые на каждый монитор в свои типы данных). Не взлетает :-(. gdb backtrace возвещает, что падает функция sws_scale(), не могу понять почему. Подскажите пожалуйста, что я делаю не так.

 , , libsws,

ryvkin-sergey
()

RSS подписка на новые темы