summaryrefslogtreecommitdiff
path: root/miavd/ffmpeg_encoder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'miavd/ffmpeg_encoder.cc')
-rw-r--r--miavd/ffmpeg_encoder.cc204
1 files changed, 204 insertions, 0 deletions
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 <config.h>
+#include "ffmpeg_encoder.h"
+#include <errno.h>
+#include "miav_config.h"
+#include <math.h>
+
+#include <ffmpeg/avcodec.h>
+#include <ffmpeg/avformat.h>
+
+#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 <unistd.h>
+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);
+}