From 2f10a73cbbe4333e2a41e87a94eda7fb3d442dc5 Mon Sep 17 00:00:00 2001 From: deva Date: Mon, 17 Mar 2008 09:10:42 +0000 Subject: Major code changes... FFMPEG introduced. Project splitup into subfolders. --- miavd/Makefile.am | 26 +++ miavd/daemon.cc | 118 ++++++++++++ miavd/daemon.h | 45 +++++ miavd/error.cc | 73 +++++++ miavd/error.h | 32 ++++ miavd/ffframe.h | 64 +++++++ miavd/ffmpeg_encoder.cc | 204 ++++++++++++++++++++ miavd/ffmpeg_encoder.h | 81 ++++++++ miavd/ffoutput.cc | 400 +++++++++++++++++++++++++++++++++++++++ miavd/ffoutput.h | 78 ++++++++ miavd/format.h | 48 +++++ miavd/img_encoder.cc | 232 +++++++++++++++++++++++ miavd/img_encoder.h | 62 ++++++ miavd/info_console.cc | 101 ++++++++++ miavd/info_console.h | 52 +++++ miavd/miav_daemon.cc | 109 +++++++++++ miavd/miav_daemon.h | 42 ++++ miavd/miavd.cc | 47 +++++ miavd/multicast_configuration.cc | 141 ++++++++++++++ miavd/multicast_configuration.h | 56 ++++++ miavd/server.cc | 137 ++++++++++++++ miavd/server.h | 37 ++++ miavd/stream.h | 61 ++++++ 23 files changed, 2246 insertions(+) create mode 100644 miavd/Makefile.am create mode 100644 miavd/daemon.cc create mode 100644 miavd/daemon.h create mode 100644 miavd/error.cc create mode 100644 miavd/error.h create mode 100644 miavd/ffframe.h create mode 100644 miavd/ffmpeg_encoder.cc create mode 100644 miavd/ffmpeg_encoder.h create mode 100644 miavd/ffoutput.cc create mode 100644 miavd/ffoutput.h create mode 100644 miavd/format.h create mode 100644 miavd/img_encoder.cc create mode 100644 miavd/img_encoder.h create mode 100644 miavd/info_console.cc create mode 100644 miavd/info_console.h create mode 100644 miavd/miav_daemon.cc create mode 100644 miavd/miav_daemon.h create mode 100644 miavd/miavd.cc create mode 100644 miavd/multicast_configuration.cc create mode 100644 miavd/multicast_configuration.h create mode 100644 miavd/server.cc create mode 100644 miavd/server.h create mode 100644 miavd/stream.h (limited to 'miavd') diff --git a/miavd/Makefile.am b/miavd/Makefile.am new file mode 100644 index 0000000..2170717 --- /dev/null +++ b/miavd/Makefile.am @@ -0,0 +1,26 @@ +bin_PROGRAMS = miavd + +miavd_LDADD = ../libmiav/libmiav.la + +miavd_SOURCES = \ + miavd.cc \ + daemon.cc \ + error.cc \ + ffoutput.cc \ + ffmpeg_encoder.cc \ + img_encoder.cc \ + info_console.cc \ + miav_daemon.cc \ + multicast_configuration.cc \ + server.cc + +EXTRA_DIST = \ + miavd.h \ + daemon.h \ + ffoutput.h \ + ffmpeg_encoder.h \ + img_encoder.h \ + info_console.h \ + miav_daemon.h \ + multicast_configuration.h \ + server.h diff --git a/miavd/daemon.cc b/miavd/daemon.cc new file mode 100644 index 0000000..6e46bd5 --- /dev/null +++ b/miavd/daemon.cc @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * daemon.cc + * + * Thu Jun 9 10:27:59 CEST 2005 + * Copyright 2005 Bent Bisballe + * deva@aasimon.org + ****************************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "daemon.h" + +#include +#include +#include +#include +#include + +// For getgrent and getgrent +#include +#include +#include + +// For strcmp +#include + +Daemon::Daemon() +{} + +Daemon::~Daemon() +{} + +int Daemon::run(const char *user, const char* group) +{ + int f; + int fd; + + // Fetch user id + int uid = -1; + struct passwd *p = getpwent(); + while(p) { + if(strcmp(p->pw_name, user) == 0) uid = p->pw_uid; + p = getpwent(); + } + if(uid == -1) { + fprintf(stderr, "Could not find user \"%s\" in /etc/passwd file.\n", user); + } + + // Fetch group id + int gid = -1; + struct group *g = getgrent(); + while(g) { + if(strcmp(g->gr_name, group) == 0) gid = g->gr_gid; + g = getgrent(); + } + if(gid == -1) { + fprintf(stderr, "Could not find group \"%s\" in /etc/group file.\n", group); + } + + chdir("/"); + umask(0); + + f = fork(); + switch(f) { + case -1: // Fork error + perror("Fork in daemon.cc"); + return 1; + + case 0: // Forked child + // Switch to given group + if(setgid(gid) != 0) { + fprintf(stderr, "Failed to change to group \"%s\" (gid: %d), quitting.\n", group, gid); + perror(""); + fprintf(stderr, "Runnning daemon as current group\n"); + } + + // Switch to given user + if(setuid(uid) != 0) { + fprintf(stderr, "Failed to change to user \"%s\" (uid: %d), quitting.\n", user, uid); + perror(""); + fprintf(stderr, "Runnning daemon as current user\n"); + } + + // Redirect stdin, stdout and stderr to /dev/null + fd = open("/dev/null", O_NOCTTY | O_RDWR, 0666); + + dup2(0, fd); + dup2(1, fd); + dup2(2, fd); + + setsid(); + + signal (SIGTERM, SIG_IGN); + signal (SIGINT, SIG_IGN); + signal (SIGHUP, SIG_IGN); + + return daemon_main(); + + default: // Parent + // exit(0); + return 0; + } +} diff --git a/miavd/daemon.h b/miavd/daemon.h new file mode 100644 index 0000000..1bd663e --- /dev/null +++ b/miavd/daemon.h @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * daemon.h + * + * Thu Jun 9 10:27:59 CEST 2005 + * Copyright 2005 Bent Bisballe + * deva@aasimon.org + ****************************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __DAEMON_H__ +#define __DAEMON_H__ + +#include + +class Daemon { +public: + Daemon(); + virtual ~Daemon(); + + /** + * Use NOBODY_GROUP and NOBODY_USER if no privileges are needed to run. + */ + int run(const char* user, const char* group); + +private: + virtual int daemon_main() = 0; +}; + +#endif/*__DAEMON_H__*/ diff --git a/miavd/error.cc b/miavd/error.cc new file mode 100644 index 0000000..02843e3 --- /dev/null +++ b/miavd/error.cc @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * error.cc + * + * Fri Dec 28 18:49:20 CET 2007 + * Copyright 2007 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of FFMpegPP. + * + * FFMpegPP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFMpegPP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FFMpegPP; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "error.h" +extern "C" { +#include +} +#include +#include + +void error(int errval, char *where) +{ + printf("Error: "); + + switch(-errval) { + case AVERROR_IO: + printf("I/O error"); + break; + + case AVERROR_NUMEXPECTED: + printf("Number syntax expected in filename."); + break; + + case AVERROR_INVALIDDATA: + printf("Invalid data found."); + break; + + case AVERROR_NOMEM: + printf("Not enough memory."); + break; + + case AVERROR_NOFMT: + printf("Unknown format."); + break; + + case AVERROR_NOTSUPP: + printf("Operation not supported."); + break; + + case AVERROR_NOENT: + printf("No such file or directory."); + break; + + default: + printf("Unknown error"); + break; + } + + printf(" in %s\n", where); +} diff --git a/miavd/error.h b/miavd/error.h new file mode 100644 index 0000000..1c72862 --- /dev/null +++ b/miavd/error.h @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * error.h + * + * Fri Dec 28 18:49:20 CET 2007 + * Copyright 2007 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of FFMpegPP. + * + * FFMpegPP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFMpegPP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FFMpegPP; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __FFMPEGPP_ERROR_H__ +#define __FFMPEGPP_ERROR_H__ + +void error(int errval, char *where); + +#endif/*__FFMPEGPP_ERROR_H__*/ diff --git a/miavd/ffframe.h b/miavd/ffframe.h new file mode 100644 index 0000000..fec820d --- /dev/null +++ b/miavd/ffframe.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * frame.h + * + * Fri Dec 28 18:09:04 CET 2007 + * Copyright 2007 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of FFMpegPP. + * + * FFMpegPP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFMpegPP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FFMpegPP; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __FFMPEGPP_FRAME_H__ +#define __FFMPEGPP_FRAME_H__ + +extern "C" { +#include +#include +} + +#include "stream.h" + +class FFFrame { +public: + FFFrame() { + avframe = NULL; + stream = NULL; + codec_context = NULL; + pts = 0; + dts = 0; + } + + // The actual frame data. + AVFrame *avframe; + + Stream *stream; + + AVCodecContext *codec_context; + + // Audio data + int16_t *pcmdata; + int pcmdatasize; + + // Timecode + int64_t pts; + int64_t dts; + +}; + +#endif/*__FFMPEGPP_FRAME_H__*/ diff --git a/miavd/ffmpeg_encoder.cc b/miavd/ffmpeg_encoder.cc new file mode 100644 index 0000000..2f73c4c --- /dev/null +++ b/miavd/ffmpeg_encoder.cc @@ -0,0 +1,204 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * mov_encoder_thread.cc + * + * Tue May 17 16:00:01 CEST 2005 + * Copyright 2005 Bent Bisballe + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of MIaV. + * + * MIaV is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MIaV is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MIaV; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include +#include "ffmpeg_encoder.h" +#include +#include "miav_config.h" +#include + +#include +#include + +#define AUDIO_BUFFER_SIZE DV_AUDIO_MAX_SAMPLES +//(DV_AUDIO_MAX_SAMPLES * sizeof(int16_t)) + +FFMpegEncoder::FFMpegEncoder(const char *clientip, const char *cpr) +{ + MIaV::info->info("FFMpegEncoder"); + + // init encoder + output = new FFOutput(cpr, clientip); + + // Init DV decoder + avcodec_init(); + + // Video + dvvcodec = avcodec_find_decoder(CODEC_ID_DVVIDEO); + if(!dvvcodec) MIaV::info->error("Could not find DV Video codec."); + + dvvcontext = avcodec_alloc_context(); + if(avcodec_open(dvvcontext, dvvcodec) < 0) MIaV::info->error("Could not open DV Video codec."); + + // Audio + dvacodec = avcodec_find_decoder(CODEC_ID_PCM_S16LE); + if(!dvacodec) MIaV::info->error("Could not find DV Audio codec."); + + dvacontext = avcodec_alloc_context(); + if(avcodec_open(dvacontext, dvacodec) < 0) MIaV::info->error("Could not open DV Audio codec."); + + frame_number = 0; + + audio_buffer[0] = (int16_t*)calloc(AUDIO_BUFFER_SIZE, sizeof(int16_t)); + audio_buffer[1] = (int16_t*)calloc(AUDIO_BUFFER_SIZE, sizeof(int16_t)); + + sin_cnt = 0; + decoder = NULL; + + // CBuffer init + cbufferdatasize = 0; + cbuffer_size = AUDIO_BUFFER_SIZE * 4; // Buffer max, 2 frames * 2 channels. + cbuffer = (int16_t *)malloc(cbuffer_size * sizeof(int16_t)); + pbegin = 0; +} + +//#include +FFMpegEncoder::~FFMpegEncoder() +{ + MIaV::info->info("~FFMpegEncoder..."); + + delete output; + + free(audio_buffer[0]); + free(audio_buffer[1]); + + free(cbuffer); + dv_decoder_free(decoder); + + MIaV::info->info("~FFMpegEncoder::done"); +} + +void FFMpegEncoder::encode(Frame* frame) +{ + if(frame_number % 250 == 0) + MIaV::info->info("Got frame %d ...", frame_number); + + if(frame == NULL) { + MIaV::info->info("FFMpegEncoder::encode - NULL frame detected."); + // Terminate + return; + } + + if(frame->endOfFrameStream) { + // MIaV::info->info("endOfStream"); + return; + } + + frame->number = frame_number; + +#if 0 + // Use to half the framerate. + if(frame_number % 2 == 0) { + frame_number ++; + return; + } +#endif + + // + // VIDEO + // + FFFrame *vfrm = new FFFrame(); + vfrm->avframe = avcodec_alloc_frame(); + vfrm->codec_context = dvvcontext; + int got_picture; + int pos = avcodec_decode_video(dvvcontext, vfrm->avframe, &got_picture, frame->data, frame->size); + if(!got_picture) + MIaV::info->warn("Decoding did not result in a picture!"); + output->writeFrame(vfrm); + + // + // AUDIO + // + FFFrame *afrm = new FFFrame(); + afrm->pcmdatasize = output->audio_st->codec->frame_size * 2 * sizeof(int16_t); + afrm->pcmdata = (int16_t*)malloc(afrm->pcmdatasize); + //afrm->avframe = avcodec_alloc_frame(); + afrm->codec_context = dvacontext; + + if(frame->mute) { + // Overwrite audiobuffer with dummy data + double volume = 1000; // Min:= 0 - Max := 32000 + double frequency = 440; // in Hz + + for(int cnt = 0; cnt < 48000/25; cnt++) { + sin_cnt++; + double sin_val = (((double)sin_cnt / (double)48000) * (double)M_PI) * frequency; + audio_buffer[0][cnt] = audio_buffer[1][cnt] = (short int)(sin(sin_val) * volume); + } + } else { + // Decode audio from dv frame + if(!decoder) { + decoder = dv_decoder_new(FALSE, FALSE, FALSE); + decoder->quality = DV_QUALITY_BEST; + + dv_parse_header(decoder, frame->data); + + decoder->system = e_dv_system_625_50; // PAL lines, PAL framerate + decoder->sampling = e_dv_sample_422; // 4 bytes y, 2 bytes u, 2 bytes v + decoder->std = e_dv_std_iec_61834; + decoder->num_dif_seqs = 12; + } + + // Decode audio using libdv + int frames = dv_decode_full_audio( decoder, frame->data, audio_buffer ); + + } + + // Write new data to cbuffer + int pend = pbegin + cbufferdatasize; + for(int i = 0; i < (48000/25)*2; i++) { + cbuffer[(pend + i) % cbuffer_size] = audio_buffer[i%2][i/2]; + } + cbufferdatasize += (48000/25)*2; + + // Read out full ffmpeg frames from cbuffer. + while(cbufferdatasize >= output->audio_st->codec->frame_size * 2) { + for(int i = 0; i < output->audio_st->codec->frame_size * 2; i++) { + afrm->pcmdata[i] = cbuffer[(pbegin + i) % cbuffer_size]; + } + + cbufferdatasize -= output->audio_st->codec->frame_size * 2; + pbegin += output->audio_st->codec->frame_size * 2; + + output->writeFrame(afrm); + } + + + frame_number ++; + + av_free(vfrm->avframe); + delete vfrm; + + free(afrm->pcmdata); + delete afrm; + + delete frame; +} + +void FFMpegEncoder::setSaveState(n_savestate savestate) +{ + output->setSaveState(savestate); +} diff --git a/miavd/ffmpeg_encoder.h b/miavd/ffmpeg_encoder.h new file mode 100644 index 0000000..8a70521 --- /dev/null +++ b/miavd/ffmpeg_encoder.h @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * mov_encoder_thread.h + * + * Tue May 17 16:00:01 CEST 2005 + * Copyright 2005 Bent Bisballe + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of MIaV. + * + * MIaV is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MIaV is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MIaV; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "config.h" +#ifndef __MIAV_FFMPEG_ENCODER_H__ +#define __MIAV_FFMPEG_ENCODER_H__ + +#include +#include +#include +#include + +#include +using namespace std; + +#include "frame.h" + +#include "ffoutput.h" + +#include "info.h" + +// For savestate_n +#include "package.h" + +#include +#include + +class FFMpegEncoder { +public: + FFMpegEncoder(const char *clientip, const char *cpr); + ~FFMpegEncoder(); + + void encode(Frame* frame); + + void setSaveState(n_savestate savestate); + +private: + FFOutput *output; + + AVCodec *dvvcodec; + AVCodecContext *dvvcontext; + + AVCodec *dvacodec; + AVCodecContext *dvacontext; + int16_t *audio_buffer[2]; + + // Audio vars + int sin_cnt; + dv_decoder_t *decoder; // DV Audio Decoder + int cbufferdatasize; + int cbuffer_size; + int16_t *cbuffer; + int pbegin; + + unsigned int frame_number; +}; + +#endif/*__MIAV_FFMPEG_ENCODER_H__*/ diff --git a/miavd/ffoutput.cc b/miavd/ffoutput.cc new file mode 100644 index 0000000..963e694 --- /dev/null +++ b/miavd/ffoutput.cc @@ -0,0 +1,400 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * ffoutput.cc + * + * Fri Dec 28 18:09:18 CET 2007 + * Copyright 2007 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of MIaV. + * + * MIaV is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MIaV is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MIaV; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "ffoutput.h" + +#include +#include +#include +#include + +#include "miav_config.h" + +#define INDEX_PACKET_HEADER_SIZE 8192 + +/* + * add a video output stream + */ +AVStream *FFOutput::add_video_stream(AVFormatContext *oc, CodecID codec_id) +{ + AVCodecContext *c; + AVStream *st; + + int stream_id = 0;//av_find_default_stream_index(oc); + st = av_new_stream(oc, stream_id); + if (!st) { + MIaV::info->error("Could not alloc video stream"); + } + + AVCodec *codec = avcodec_find_encoder(codec_id); + if(!codec) { + MIaV::info->error("Could not find video encoder codec."); + } + + AVFormatParameters parms; + parms.mpeg2ts_raw = 1; + parms.mpeg2ts_compute_pcr = 1; + if (av_set_parameters(oc, NULL) < 0) { + MIaV::info->error("Invalid output format parameters."); + } + + // Get config values + int bitrate = config->readInt("video_bitrate"); + int num_threads = config->readInt("encoding_threads"); + + + c = st->codec; + c->codec_id = codec_id; + c->bit_rate = bitrate * 1000; + // c->width = 480; c->height = 320; + c->width = 720; c->height = 576; + c->time_base= (AVRational){1,25}; + //c->time_base= (AVRational){2,25}; + c->gop_size = 12; // Emit one intra frame every twelve frames at most. + c->pix_fmt = PIX_FMT_YUV420P; //NONE + c->codec_type = CODEC_TYPE_VIDEO; + c->max_b_frames = 0; + // c->flags2 |= CODEC_FLAG2_8X8DCT; + c->strict_std_compliance = FF_COMPLIANCE_VERY_STRICT; + + c->debug = 0; + c->debug_mv = 0; + + c->rtp_payload_size = 1500; + c->rtp_mode = 1; + + c->thread_count = num_threads; + + if(avcodec_open(c, codec) < 0) { + MIaV::info->error("Could not open video encoder codec."); + } + + if(c->thread_count > 1) avcodec_thread_init(c, c->thread_count); + + /* // Later version of ffmpeg + AVProgram *p = av_new_program(oc, stream_id); + p->provider_name = "Aasimon.org"; + p->name = "MIaV"; + */ + + + snprintf(oc->title, 512, "MIaV"); + snprintf(oc->author, 512, "Aasimon.org"); + /* + char copyright[512]; + char comment[512]; + char album[512]; + int year; + int track; + char genre[32]; +*/ + return st; +} + + +/* + * add an audio output stream + */ +AVStream *FFOutput::add_audio_stream(AVFormatContext *oc, CodecID codec_id) +{ + AVCodecContext *c; + AVStream *st; + + int stream_id = 0;//av_find_default_stream_index(oc); + st = av_new_stream(oc, stream_id + 1); + if (!st) { + MIaV::info->error("Could not alloc audio stream"); + } + + AVCodec *codec = avcodec_find_encoder(codec_id); + if(!codec) { + MIaV::info->error("Could not find audio encoder codec."); + } + + // Get config values + int bitrate = config->readInt("audio_bitrate"); + + c = st->codec; + c->codec_id = codec_id; + c->codec_type = CODEC_TYPE_AUDIO; + c->bit_rate = bitrate * 1000; + c->sample_rate = 48000; + c->channels = 2; + c->sample_fmt = SAMPLE_FMT_S16; + + c->debug = 0; + + c->rtp_payload_size = 1500; + c->rtp_mode = 1; + + if(avcodec_open(st->codec, codec) < 0) { + MIaV::info->error("Could not open audio encoder codec."); + } + + return st; +} + +FFOutput::FFOutput(const char *cpr, const char *clientip) +{ + avcodec_init(); + av_register_all(); + + // Get filename + // Create path and filename + char fname[256]; + string *server_root; + char birthmonth[3]; + char date[32]; + + // Get server root + server_root = config->readString("server_movie_root"); + + // Copy the bytes representing the birth month from the cpr + // [dd][mm][yy]-[nn][nn] + strncpy(birthmonth, &cpr[2], 2); + birthmonth[2] = 0; + + // Create date (today) in [yyyy][mm][dd] + struct tm *ltime; + time_t t = time(NULL); + ltime = localtime(&t); + sprintf(date, "%.4d%.2d%.2d", + ltime->tm_year + 1900, + ltime->tm_mon + 1, // Ranging from 0 to 11 + ltime->tm_mday); + + sprintf(fname, "%s/%s/%s/%s-%s-", server_root->c_str(), birthmonth, cpr, cpr, date); + + file = new File(fname, "avi", MIaV::info); + + open(); + + maxfilesize = -1;//10000000; +} + +FFOutput::~FFOutput() +{ + MIaV::info->info("~FFOutput..."); + + close(); + + if(video_st->codec->thread_count > 1) avcodec_thread_free(video_st->codec); + if(net_video_st->codec->thread_count > 1) avcodec_thread_free(net_video_st->codec); + + delete file; + + MIaV::info->info("~FFOutput...done"); +} + +void FFOutput::open() +{ + enum CodecID vcodecid = CODEC_ID_H264; + enum CodecID acodecid = CODEC_ID_MP3; + + // + // Output file + // + + filename = file->Open(); + + oc = av_alloc_format_context(); + + oc->oformat = guess_format(NULL, filename.c_str(), NULL); + if (!oc->oformat) { + MIaV::info->error("guess_format failed on %s", filename.c_str()); + } + + video_st = add_video_stream(oc, vcodecid); + audio_st = add_audio_stream(oc, acodecid); + + oc->flags |= AVFMT_FLAG_GENPTS; + + // some formats want stream headers to be seperate + if(!strcmp(oc->oformat->name, "mp4")) { + // || !strcmp(oc->oformat->name, "mov") || !strcmp(oc->oformat->name, "3gp")) + video_st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; + } + + // dump_format(oc, 0, filename.c_str(), 1); + + // open the output file, if needed + if (!(oc->oformat->flags & AVFMT_NOFILE)) { + if (url_fopen(&(oc->pb), filename.c_str(), URL_WRONLY) < 0) { + MIaV::info->error("Could not open '%s': %s", filename.c_str(), strerror(errno)); + } + } + + av_write_header(oc); + keyframes = 0; + if(maxfilesize != -1) maxfilesize = maxfilesize - oc->pb.pos; + + + // + // RTSP + // + + stream_oc = av_alloc_format_context(); + + char streamformat[] = "mpegts";//mpegts";//"m4v"; // "mpegts"; "rm"; + stream_oc->oformat = guess_stream_format(streamformat, NULL, NULL); + if (!stream_oc->oformat) { + MIaV::info->error("guess_format failed on %s", streamformat); + } + + net_video_st = add_video_stream(stream_oc, vcodecid); + net_audio_st = add_audio_stream(stream_oc, acodecid); + + stream_oc->flags |= AVFMT_FLAG_GENPTS; + + // open the output file, if needed + if (!(stream_oc->oformat->flags & AVFMT_NOFILE)) { + char streamname[] = "rtp://224.0.0.1:1234"; + if (url_fopen(&(stream_oc->pb), streamname, URL_WRONLY) < 0) { + MIaV::info->error("Could not open '%s': %s", streamname, strerror(errno)); + } + } + av_write_header(stream_oc); + + +} + +void FFOutput::close() +{ + av_write_trailer(oc); + if (!(oc->oformat->flags & AVFMT_NOFILE)) { + url_fclose(&(oc->pb)); + } + + avcodec_close(audio_st->codec); + avcodec_close(video_st->codec); + av_free(oc); + + av_write_trailer(stream_oc); + if (!(stream_oc->oformat->flags & AVFMT_NOFILE)) { + url_fclose(&(stream_oc->pb)); + } + + avcodec_close(net_audio_st->codec); + avcodec_close(net_video_st->codec); + av_free(stream_oc); +} + +#ifndef INT64_C +#define INT64_C(c) (c ## LL) +#endif + +void FFOutput::writeFrame(FFFrame *frame) +{ + // return; + bit_buffer_size = 720*576*4;//video_st->codec->bit_rate * 1024 * 10; + bit_buffer = (uint8_t*)malloc(bit_buffer_size); + + if( maxfilesize != -1 && + oc->pb.pos + (keyframes * 170) + INDEX_PACKET_HEADER_SIZE > maxfilesize) { // Too big? + close(); + open(); + } + + if(frame == NULL) return; + int ret = 0; + int stream_index = -1; + int64_t pts; + int64_t dts; + int pos = 0; + + + // printf("Now: %lld\n", av_gettime()); + if(frame->pts == AV_NOPTS_VALUE) frame->pts = av_gettime(); + if(frame->pts == 0) frame->pts = av_gettime(); + + switch(frame->codec_context->codec->type) { + case CODEC_TYPE_VIDEO: + stream_index = 0; + ret = avcodec_encode_video(net_video_st->codec, + bit_buffer, + bit_buffer_size, + frame->avframe); + pts = net_video_st->codec->coded_frame->pts; + //pts = vpts; + //vpts++; + break; + + case CODEC_TYPE_AUDIO: + stream_index = 1; + ret = avcodec_encode_audio(net_audio_st->codec, + bit_buffer, + bit_buffer_size, + frame->pcmdata); + pts = net_audio_st->codec->coded_frame->pts; + // apts += 48000/25; + break; + + default: + ret = 0; + break; + } + + // printf("Now: %lld\n", av_gettime()); + if(pts == AV_NOPTS_VALUE) pts = av_gettime(); + if(pts == 0) pts = av_gettime(); + + if(ret > 0){ + AVPacket *pkt = (AVPacket*)malloc(sizeof(AVPacket)); + av_init_packet(pkt); + + // dts = pts; + // dts++; + + pkt->pts = pts; + pkt->dts = 0;//AV_NOPTS_VALUE; + pkt->stream_index = stream_index; + if(stream_index == 1) pkt->flags |= PKT_FLAG_KEY; + + pkt->data = bit_buffer; + pkt->size = ret; + + if(video_st->codec->coded_frame && video_st->codec->coded_frame->key_frame) { + pkt->flags |= PKT_FLAG_KEY; + keyframes++; + } + + if (!(oc->oformat->flags & AVFMT_NOFILE)) { + av_interleaved_write_frame(oc, pkt); + //av_write_frame(oc, pkt); + } + if (!(stream_oc->oformat->flags & AVFMT_NOFILE)) { + av_interleaved_write_frame(stream_oc, pkt); + //av_write_frame(oc, pkt); + } + free(pkt->data); + free(pkt); + } +} + +void FFOutput::setSaveState(n_savestate savestate) +{ + file->setSaveState(savestate); +} diff --git a/miavd/ffoutput.h b/miavd/ffoutput.h new file mode 100644 index 0000000..ce4f83f --- /dev/null +++ b/miavd/ffoutput.h @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * ffoutput.h + * + * Fri Dec 28 18:09:17 CET 2007 + * Copyright 2007 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of MIaV. + * + * MIaV is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MIaV is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MIaV; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __MIAV_FFOUTPUT_H__ +#define __MIAV_FFOUTPUT_H__ + +extern "C" { +#include +#include +} + +#include "ffframe.h" +#include "format.h" + +#include +#include + +// For n_savestate +#include "package.h" + +class FFOutput { +public: + FFOutput(const char *cpr, const char *clientip); + ~FFOutput(); + + void writeFrame(FFFrame *frame); + void setSaveState(n_savestate savestate); + + AVStream *audio_st; + +private: + void open(); + void close(); + + std::string filename; + File *file; + + AVStream *add_video_stream(AVFormatContext *oc, CodecID codec_id); + AVStream *add_audio_stream(AVFormatContext *oc, CodecID codec_id); + + long long int maxfilesize; + unsigned int keyframes; + + AVFormatContext *stream_oc; + AVFormatContext *oc; + AVStream *video_st; + // AVStream *audio_st; + AVStream *net_video_st; + AVStream *net_audio_st; + + size_t bit_buffer_size; + uint8_t *bit_buffer; +}; + +#endif/*__MIAV_FFOUTPUT_H__*/ diff --git a/miavd/format.h b/miavd/format.h new file mode 100644 index 0000000..722b6b7 --- /dev/null +++ b/miavd/format.h @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * format.h + * + * Sat Dec 29 12:59:16 CET 2007 + * Copyright 2007 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of FFMpegPP. + * + * FFMpegPP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFMpegPP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FFMpegPP; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __FFMPEGPP_FORMAT_H__ +#define __FFMPEGPP_FORMAT_H__ + +typedef enum { + FMT_MPEG4, + FMT_MPEG2, + FMT_MPEG1, + FMT_MJPEG, + FMT_H264 +} VFormat; + +typedef enum { + FMT_AAC, + FMT_MP3, + FMT_MP2, + FMT_PCM, + FMT_VORBIS, + FMT_AC3 +} AFormat; + + +#endif/*__FFMPEGPP_FORMAT_H__*/ diff --git a/miavd/img_encoder.cc b/miavd/img_encoder.cc new file mode 100644 index 0000000..b326749 --- /dev/null +++ b/miavd/img_encoder.cc @@ -0,0 +1,232 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * img_encoder.cc + * + * Mon Nov 15 19:45:07 CET 2004 + * Copyright 2004 Bent Bisballe + * deva@aasimon.org + ****************************************************************************/ + +/* + * Originally from: + * RTVideoRec Realtime video recoder and encoder for Linux + * + * Copyright (C) 2004 B. Stultiens + * Copyright (C) 2004 Koen Otter and Glenn van der Meyden + */ + +/* + * This file is part of MIaV. + * + * MIaV is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MIaV is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MIaV; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "img_encoder.h" +#include + +#include +#include +#include +#include +#include + +#include + +#include "debug.h" + +extern "C" { +#include +} + +#include "jpeg_mem_dest.h" + +// Use libdv +#include +#include + +ImgEncoder::ImgEncoder(const char* cpr) +{ + // Create path and filename + char filename[256]; + string *server_root; + char birthmonth[3]; + char date[32]; + char encrypted_cpr[32]; + + // Get server root + server_root = config->readString("server_image_root"); + + // Copy the bytes representing the birth month from the cpr + // [dd][mm][yy]-[nn][nn] + strncpy(birthmonth, &cpr[2], 2); + birthmonth[2] = 0; + + // Create date (today) in [yyyy][mm][dd] + struct tm *ltime; + time_t t = time(NULL); + ltime = localtime(&t); + sprintf(date, "%.4d%.2d%.2d", + ltime->tm_year + 1900, + ltime->tm_mon, + ltime->tm_mday); + + // Create 'encrypted' cpr, reverse numbers, skip month, and subtract from 9 + // [d1][d2][m1][m2][y1][y2]-[n1][n2][n3][n4] + // => + // [9-n4][9-n3][9-n2][9-n1][9-y2][9-y1][9-d2][9-d1] + memset(encrypted_cpr, 0, sizeof(encrypted_cpr)); + int p = strlen(cpr) - 1; + int cnt = 0; + while(p) { + encrypted_cpr[cnt] = cpr[p]; + p--; + if(p == 2) p--; + if(cpr[p] == '-' || p == 3) p--; + cnt++; + } + + sprintf(filename, "%s/%s/%s/%s-%s-", server_root->c_str(), birthmonth, encrypted_cpr, cpr, date); + char extension[] = "jpg"; + + // + // Open unique file. + // + fd = -1; + int num = 0; + char buf[512]; + + while(fd == -1 && num < 999) { + sprintf(buf, "%s%.3d.%s", filename, num, extension); + + // Try to open exclusively, fails if file already exists. + fd = open(buf, O_CREAT | O_WRONLY | O_ASYNC | O_EXCL, //| O_LARGEFILE + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + + if(fd == -1) { + switch(errno) { + case EEXIST: + num ++; + break; + default: + MIaV::info->error("Something is wrong with the path [%s] - %s!", filename, strerror(errno)); + return; + } + } + } + + MIaV::info->info("Writing screenshot to file: %s", buf); + +} + + +ImgEncoder::~ImgEncoder() +{ + if(fd != -1) close(fd); +} + + +void ImgEncoder::encode(Frame *dvframe, int quality) +{ + unsigned char rgb[720*576*4]; + + getRGB(dvframe, rgb); + writeJPEGFile(quality, rgb, 720, 576); +} + + +void ImgEncoder::writeJPEGFile(int quality, unsigned char *rgb, int image_width, int image_height) +{ + JSAMPLE *image_buffer = (JSAMPLE*)rgb; + + size_t buffersize = (image_width * image_height * 3) + JPEG_HEADER_PAD; + char *jpeg_output_buffer = new char [buffersize]; + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + + JSAMPROW row_pointer[1]; // pointer to JSAMPLE row[s] + int row_stride; // physical row width in image buffer + + // Allocate and initialize JPEG compression object + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + + // Specify data destination (see jpeg_mem_dest) + jpeg_mem_dest(&cinfo, jpeg_output_buffer, &buffersize); + + // Set compression parameters + cinfo.image_width = image_width; // image width and height, in pixels + cinfo.image_height = image_height; + cinfo.input_components = 3; // # of color components per pixel + cinfo.in_color_space = JCS_RGB; // colorspace of input image + + jpeg_set_defaults(&cinfo); + + jpeg_set_quality(&cinfo, quality, TRUE); // limit to baseline-JPEG values + + // Start compressor + jpeg_start_compress(&cinfo, TRUE); + + // While (scan lines remain to be written) + row_stride = image_width * 3; // JSAMPLEs per row in image_buffer + + while (cinfo.next_scanline < cinfo.image_height) { + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + // Finish compression + jpeg_finish_compress(&cinfo); + + // Release JPEG compression object + jpeg_destroy_compress(&cinfo); + + // MIaV::info->info("JPEG buffersize: %d", buffersize); + + if(fd != -1) write(fd, jpeg_output_buffer, buffersize); + + delete jpeg_output_buffer; +} + +void ImgEncoder::getRGB(Frame *frame, unsigned char *rgb) +{ + unsigned char *pixels[3]; + int pitches[3]; + + pixels[ 0 ] = rgb; + pixels[ 1 ] = NULL; + pixels[ 2 ] = NULL; + + pitches[ 0 ] = 720 * 3; + pitches[ 1 ] = 0; + pitches[ 2 ] = 0; + + dv_decoder_t *decoder = dv_decoder_new(FALSE/*this value is unused*/, FALSE, FALSE); + decoder->quality = DV_QUALITY_BEST; + + dv_parse_header(decoder, frame->data); + + decoder->system = e_dv_system_625_50; // PAL lines, PAL framerate + decoder->sampling = e_dv_sample_422; // 4 bytes y, 2 bytes u, 2 bytes v + decoder->std = e_dv_std_iec_61834; + decoder->num_dif_seqs = 12; + + // libdv img decode to rgb + dv_decode_full_frame(decoder, + frame->data, + e_dv_color_rgb, + pixels, + pitches); + + dv_decoder_free(decoder); +} diff --git a/miavd/img_encoder.h b/miavd/img_encoder.h new file mode 100644 index 0000000..9f722f4 --- /dev/null +++ b/miavd/img_encoder.h @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * img_encoder.h + * + * Mon Nov 15 19:45:07 CET 2004 + * Copyright 2004 Bent Bisballe + * deva@aasimon.org + ****************************************************************************/ + +/* + * Originally from: + * RTVideoRec Realtime video recoder and encoder for Linux + * + * Copyright (C) 2004 B. Stultiens + */ + +/* + * This file is part of MIaV. + * + * MIaV is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MIaV is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MIaV; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +//#include "config.h" +#ifndef __RTVIDEOREC_IMGENCODER_H +#define __RTVIDEOREC_IMGENCODER_H + +#include + +#include "frame.h" +#include "util.h" + +#define VIDEO_BUFFER_SIZE (1024*1024) // FIXME: One size fits all... +#define JPEG_HEADER_PAD 500 + +class ImgEncoder { +public: + ImgEncoder(const char* cpr); + ~ImgEncoder(); + void encode(Frame *frame, int quality); + void writeJPEGFile(int quality, + unsigned char *image_buffer, // Points to large array of R,G,B-order data + int image_width, // Number of columns in image + int image_height); // Number of rows in image + +private: + int fd; + void getRGB(Frame *frame, unsigned char *rgb); +}; + +#endif /*__RTVIDEOREC_IMGENCODER_H*/ + diff --git a/miavd/info_console.cc b/miavd/info_console.cc new file mode 100644 index 0000000..ce406fb --- /dev/null +++ b/miavd/info_console.cc @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * info_console.cc + * + * Tue May 3 09:35:03 CEST 2005 + * Copyright 2005 Bent Bisballe + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of MIaV. + * + * MIaV is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MIaV is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MIaV; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include +#include "info_console.h" + +#include "miav_config.h" + +#include +#include + +InfoConsole::InfoConsole(MiavConfig *c): Info() +{ + this->config = c; + log_filename = *(this->config->readString("server_log_file")); +} + +InfoConsole::~InfoConsole() +{ + pthread_mutex_destroy(&mutex); +} + +void InfoConsole::error(char *fmt, ...) +{ + char buf[1024]; + + pthread_mutex_lock(&mutex); + // Beginning of safezone + + va_list argp; + va_start(argp, fmt); + // fprintf(stderr, "Error: ["); vfprintf(stderr, fmt, argp); fprintf(stderr, "]\n"); fflush(stderr); + vsprintf(buf, fmt, argp); + va_end(argp); + + // End of safezone + pthread_mutex_unlock(&mutex); + + log("Error: %s", buf); +} + +void InfoConsole::warn(char *fmt, ...) +{ + char buf[1024]; + + pthread_mutex_lock(&mutex); + // Beginning of safezone + + va_list argp; + va_start(argp, fmt); + // fprintf(stderr, "Warning: ["); vfprintf(stderr, fmt, argp); fprintf(stderr, "]\n"); fflush(stderr); + vsprintf(buf, fmt, argp); + va_end(argp); + + // End of safezone + pthread_mutex_unlock(&mutex); + + log("Warning: %s", buf); +} + +void InfoConsole::info(char *fmt, ...) +{ + char buf[1024]; + + pthread_mutex_lock(&mutex); + // Beginning of safezone + + va_list argp; + va_start(argp, fmt); + // fprintf(stderr, "Info: ["); vfprintf(stderr, fmt, argp); fprintf(stderr, "]\n"); fflush(stderr); + vsprintf(buf, fmt, argp); + va_end(argp); + + // End of safezone + pthread_mutex_unlock(&mutex); + + log("Info: %s", buf); +} diff --git a/miavd/info_console.h b/miavd/info_console.h new file mode 100644 index 0000000..43bb435 --- /dev/null +++ b/miavd/info_console.h @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * info_console.h + * + * Tue May 3 09:35:03 CEST 2005 + * Copyright 2005 Bent Bisballe + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of MIaV. + * + * MIaV is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MIaV is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MIaV; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "config.h" +#ifndef __MIAV_INFO_CONSOLE_H__ +#define __MIAV_INFO_CONSOLE_H__ + +#include "info.h" + +#include "miav_config.h" + +#include +#include + +#include +using namespace std; + +class InfoConsole: public Info { +public: + InfoConsole(MiavConfig *config); + ~InfoConsole(); + + void error(char* fmt, ...); + void warn(char* fmt, ...); + void info(char* fmt, ...); + +}; + +#endif/*__MIAV_INFO_CONSOLE_H__*/ diff --git a/miavd/miav_daemon.cc b/miavd/miav_daemon.cc new file mode 100644 index 0000000..7f32436 --- /dev/null +++ b/miavd/miav_daemon.cc @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * miav_daemon.cc + * + * Thu Jun 9 11:14:19 CEST 2005 + * Copyright 2005 Bent Bisballe + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of MIaV. + * + * MIaV is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MIaV is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MIaV; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include +#include "miav_daemon.h" + +#include "info_console.h" +#include "miav_config.h" + +#include "server.h" +#include "socket.h" + +#include +#include + +MiavDaemon::MiavDaemon() +{} + +MiavDaemon::~MiavDaemon() +{} + +int MiavDaemon::daemon_main() +{ + MiavConfig cfg(ETC"/miav.conf", NULL); + InfoConsole info(&cfg); + MIaV::setInfo(&info); + config = new MiavConfig(ETC"/miav.conf", &info); + + int port = config->readInt("server_port"); + pid_t childpid; // variable to store the child's pid + + signal(SIGCLD, SIG_IGN); // Ved SIGCHILD til IGNORE maa wait/waitpid ikke kaldes + // (ellers kommer der kernel-brok) + + info.info("Starting MIaV server v. %s", VERSION); + info.info("Listening on port %d", port); + Socket *socket = new Socket(port, &info); + + if(socket->hasError()) { + info.error("Listening socket has errors, quitting."); + delete socket; + return 1; + } + + while(1) { + Socket *csocket = new Socket(socket->slisten()); + + if(socket->hasError()) { + info.error("Server socket has errors, quitting."); + delete csocket; + break; + } + + if(csocket->hasError()) { + info.error("Child socket has errors, quitting."); + delete csocket; + break; + } + + if(!csocket->isConnected()) { + info.error("Child socket is not connected, quitting."); + delete csocket; + break; + } + + childpid = fork(); + + switch(childpid) { + case -1: // fork() returns -1 on failure + info.log("Fork error: %s", strerror(errno)); + exit(1); + case 0: // fork() returns 0 to the child process + delete socket; // Close listen socket. + newConnection(csocket); + delete csocket; // Close communication socket. + exit(0); + + default: // fork() returns new pid to the parent process + break; + } + } + + delete socket; + return 0; +} + diff --git a/miavd/miav_daemon.h b/miavd/miav_daemon.h new file mode 100644 index 0000000..6ab469e --- /dev/null +++ b/miavd/miav_daemon.h @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * miav_daemon.h + * + * Thu Jun 9 11:14:19 CEST 2005 + * Copyright 2005 Bent Bisballe + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of MIaV. + * + * MIaV is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MIaV is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MIaV; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "config.h" +#ifndef __MIAV_MIAV_DAEMON_H__ +#define __MIAV_MIAV_DAEMON_H__ + +#include "daemon.h" + +class MiavDaemon: public Daemon { +public: + MiavDaemon(); + ~MiavDaemon(); + +private: + int daemon_main(); +}; + +#endif/*__MIAV_MIAV_DAEMON_H__*/ diff --git a/miavd/miavd.cc b/miavd/miavd.cc new file mode 100644 index 0000000..29c02f2 --- /dev/null +++ b/miavd/miavd.cc @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * miav.cc + * + * Sat Aug 21 17:32:24 2004 + * Copyright 2004 deva + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of MIaV. + * + * MIaV is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MIaV is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MIaV; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include + +#include "miav_daemon.h" + +#include "miav_config.h" + +#include "info_console.h" + +#include + +int main(int argc, char *argv[]) +{ + MiavDaemon daemon; + + MiavConfig cfg(ETC"/miav.conf", NULL); + + string *user = cfg.readString("server_user"); + string *group = cfg.readString("server_group"); + + return daemon.run(user->c_str(), group->c_str()); +} diff --git a/miavd/multicast_configuration.cc b/miavd/multicast_configuration.cc new file mode 100644 index 0000000..969faca --- /dev/null +++ b/miavd/multicast_configuration.cc @@ -0,0 +1,141 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * multicast_configuration.cc + * + * Wed Oct 12 10:12:11 CEST 2005 + * Copyright 2005 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of MIaV. + * + * MIaV is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MIaV is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MIaV; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "config.h" +#include "multicast_configuration.h" + +MulticastConfiguration::MulticastConfiguration(Info *info, char *file) + : MiavConfig(file, info) +{ + mcastconf_t conf; + + // Create the default values. + global_conf.addr = "224.0.0.1"; + global_conf.port = 1234; + global_conf.enabled = false; + global_conf.with_audio = false; + + bool global = true; + + _cfg *cfg = configs; + + // Build the client list + while(cfg) { + if(strcmp(cfg->name->c_str(), "client") == 0) { + if(!global) confs.push_back(conf); + + // Reset the configuration to the defaults + conf.client = *(cfg->stringval); + conf.addr = global_conf.addr; + conf.port = global_conf.port; + conf.enabled = global_conf.enabled; + conf.with_audio = global_conf.with_audio; + + global = false; + } + if(strcmp(cfg->name->c_str(), "address") == 0) { + if(global) global_conf.addr = *(cfg->stringval); + else conf.addr = *(cfg->stringval); + } + if(strcmp(cfg->name->c_str(), "port") == 0) { + if(global) global_conf.port = cfg->intval; + else conf.port = cfg->intval; + } + if(strcmp(cfg->name->c_str(), "enabled") == 0) { + if(global) global_conf.enabled = cfg->boolval; + else conf.enabled = cfg->boolval; + } + if(strcmp(cfg->name->c_str(), "with_audio") == 0) { + if(global) global_conf.with_audio = cfg->boolval; + else conf.with_audio = cfg->boolval; + } + cfg = cfg->next; + } + if(!global) confs.push_back(conf); + + // Show the configuration in the log file . + info->info("Global - Enabled: %s - Addr: %s - Port: %d - WithAudio: %s", + global_conf.enabled?"Yes\0":"No\0", + global_conf.addr.c_str(), + global_conf.port, + global_conf.with_audio?"Yes\0":"No\0"); + + for(unsigned int cnt = 0; cnt < confs.size(); cnt++) { + info->info("Client: %s - Enabled: %s - Addr: %s - Port: %d - WithAudio: %s", + confs[cnt].client.c_str(), + confs[cnt].enabled?"Yes\0":"No\0", + confs[cnt].addr.c_str(), + confs[cnt].port, + confs[cnt].with_audio?"Yes\0":"No\0"); + } + + info->info("Chosing:"); +} + +MulticastConfiguration::~MulticastConfiguration() +{ +} + +mcastconf_t &MulticastConfiguration::getConf(char *client) +{ + for(unsigned int cnt = 0; cnt < confs.size(); cnt++) { + if(strcmp(confs[cnt].client.c_str(), client) == 0) + return confs[cnt]; + } + + return global_conf; +} + +#ifdef __TEST_MULTICAST_CONFIGURATION +#include "info_simple.h" + +int main(int argc, char *argv[]) { + if(argc < 2) { + fprintf(stderr, "usage:\n\t%s [filename]\n", argv[0]); + return 1; + } + + InfoSimple info; + MulticastConfiguration conf(&info, argv[1]); + + mcastconf_t mcconf = conf.getConf("192.168.0.11"); + + info.warn("Client: %s - Enabled: %s - Addr: %s - Port: %d", + mcconf.client.c_str(), + mcconf.enabled?"Yes\0":"No\0", + mcconf.addr.c_str(), + mcconf.port); + + mcconf = conf.getConf("192.168.0.0"); + + info.warn("Client: %s - Enabled: %s - Addr: %s - Port: %d", + mcconf.client.c_str(), + mcconf.enabled?"Yes\0":"No\0", + mcconf.addr.c_str(), + mcconf.port); +} + +#endif/* __TEST_MULTICAST_CONFIGURATION*/ diff --git a/miavd/multicast_configuration.h b/miavd/multicast_configuration.h new file mode 100644 index 0000000..3fa7ef1 --- /dev/null +++ b/miavd/multicast_configuration.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * multicast_configuration.h + * + * Wed Oct 12 10:12:11 CEST 2005 + * Copyright 2005 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of MIaV. + * + * MIaV is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MIaV is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MIaV; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "config.h" +#ifndef __MIAV_MULTICAST_CONFIGURATION_H__ +#define __MIAV_MULTICAST_CONFIGURATION_H__ + +#include "miav_config.h" + +#include +#include + +typedef struct { + std::string client; + std::string addr; + bool enabled; + int port; + bool with_audio; +} mcastconf_t; + +class MulticastConfiguration : private MiavConfig { +public: + MulticastConfiguration(Info *info, char *file); + ~MulticastConfiguration(); + + mcastconf_t &getConf(char *client); + +private: + std::vector confs; + mcastconf_t global_conf; +}; + +#endif/*__MIAV_MULTICAST_CONFIGURATION_H__*/ diff --git a/miavd/server.cc b/miavd/server.cc new file mode 100644 index 0000000..9180c3d --- /dev/null +++ b/miavd/server.cc @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * server.cc + * + * Mon Nov 8 11:35:01 CET 2004 + * Copyright 2004 Bent Bisballe + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of MIaV. + * + * MIaV is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MIaV is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MIaV; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "server.h" +#include "miav.h" + +#include +#include + +// For mkdir +#include +#include + +// For unlink +#include + +// For errno +#include + +// For inet_ntoa +#include +#include +#include + +#include "miav_config.h" + +#include "img_encoder.h" + +#include "server_status.h" + +#include "ffmpeg_encoder.h" + +#include "dv.h" + +void newConnection(Socket *socket) +{ + char cpr[256]; + char clientip[64]; + bool hasCpr = false; + ServerStatus status(MIaV::info); + + n_savestate savestate = LATER; + n_header h; + Frame *frame; + Frame *freeze_frame = NULL; + FFMpegEncoder *enc = NULL; + + frame = new Frame(NULL, DVPACKAGE_SIZE); + + MIaV::info->info("CONNECTION OPENED"); + MIaV::info->info("New connection (%s)", inet_ntoa(socket->socketaddr.sin_addr)); + + sprintf(clientip, "%s", inet_ntoa(socket->socketaddr.sin_addr)); + + Network network = Network(socket, MIaV::info); + while(int ret = network.recvPackage(&h, frame->data, frame->size)) { + status.checkPoint(); + + if(ret == -1) { + MIaV::info->error("A network error ocurred, terminating session"); + break; + } + + frame->mute = h.header.h_data.mute; + + if(!hasCpr) { + sprintf(cpr, h.header.h_data.cpr); + hasCpr = true; + } + + if(h.header.h_data.snapshot) { + if(freeze_frame) { + ImgEncoder(cpr).encode(freeze_frame, 100); + delete freeze_frame; + freeze_frame = NULL; + } else { + ImgEncoder(cpr).encode(frame, 100); + } + } + + if(h.header.h_data.savestate != NO_CHANGE) { + savestate = h.header.h_data.savestate; + MIaV::info->info("GOT SAVESTATE FROM NETWORK: %d", savestate ); + } + + if(h.header.h_data.freeze) { + if(freeze_frame) delete freeze_frame; + // copy the frame into another temporary one. + freeze_frame = new Frame(frame->data, frame->size); + } + + // This one must be last! + if(h.header.h_data.record) { + if(!enc) enc = new FFMpegEncoder(clientip, cpr); + enc->encode(frame); + } + + frame = new Frame(NULL, DVPACKAGE_SIZE); + } + + MIaV::info->info("Closing connection..."); + + // No encoder exists, if this is a pure snapshot (image) connection. + if(enc) { + enc->setSaveState(savestate); + // Send end of stream frame. + frame->endOfFrameStream = true; + enc->encode(frame); + + delete enc; + } + + MIaV::info->info("CONNECTION CLOSED"); +} diff --git a/miavd/server.h b/miavd/server.h new file mode 100644 index 0000000..38015ba --- /dev/null +++ b/miavd/server.h @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * server.h + * + * Mon Nov 8 11:35:01 CET 2004 + * Copyright 2004 Bent Bisballe + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of MIaV. + * + * MIaV is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MIaV is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MIaV; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __SERVER_H__ +#define __SERVER_H__ + +#include "socket.h" + +#include "info.h" + +void newConnection(Socket *s); + + +#endif/*__SERVER_H__*/ diff --git a/miavd/stream.h b/miavd/stream.h new file mode 100644 index 0000000..a929243 --- /dev/null +++ b/miavd/stream.h @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * stream.h + * + * Sun Dec 30 10:37:31 CET 2007 + * Copyright 2007 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of FFMpegPP. + * + * FFMpegPP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFMpegPP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FFMpegPP; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __FFMPEGPP_STREAM_H__ +#define __FFMPEGPP_STREAM_H__ + +extern "C" { +#include +#include +} + +#include + +class Stream { +public: + Stream() { + stream = NULL; + codec_context = NULL; + codec = NULL; + index = -1; + unknown_stream = true; + } + + // Information about the stream. + AVStream *stream; + int index; + + bool unknown_stream; + + // The codec context and its codec, needed to decode this stream. + AVCodecContext *codec_context; + AVCodec *codec; +}; + +typedef std::map< int, Stream* > Streams; + + +#endif/*__FFMPEGPP_STREAM_H__*/ -- cgit v1.2.3