/* -*- 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); }