Доброго времени суток, товарищи. Я столкнулся с проблемой, которую, видимо из-за отсутствия опыта и рук заточенных под си, не могу решить.
Пишу программный видеорегистратор. На данном этапе состоит из заголовочного файла 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 */
/*
* 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(), не могу понять почему. Подскажите пожалуйста, что я делаю не так.