diff options
Diffstat (limited to 'server/libfame_wrapper.cc')
-rw-r--r-- | server/libfame_wrapper.cc | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/server/libfame_wrapper.cc b/server/libfame_wrapper.cc new file mode 100644 index 0000000..a663df6 --- /dev/null +++ b/server/libfame_wrapper.cc @@ -0,0 +1,273 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * libfame_wrapper.cc + * + * Sat Jul 2 11:11:31 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 "libfame_wrapper.h" + +#include <errno.h> + +#include "miav_config.h" +#include "frame.h" + +LibFAMEWrapper::LibFAMEWrapper(Info *i) +{ + info = i; + + // FIXME: Hmmm... should this be detected somewhere?! + int w = 720; + int h = 576; + + // Initialize yuv structure. + yuv.w = w; + yuv.h = h; + yuv.p = w; + yuv.y = new unsigned char [w*h * 2]; + yuv.u = new unsigned char [w*h];// [w*h/4] + yuv.v = new unsigned char [w*h];// [w*h/4] + + calc_bitrate = 0; + frame_number = 0; + + ////////////LIBDV STUFF/////////////// + + dvdecoder = NULL; // Initialize in encode method + + /////////LIBFAME STUFF/////////// + + // Allocate the output buffer. +// fame_buffer = new unsigned char [FAME_BUFFER_SIZE]; + + // Open a new session of the fame library. + // (If initialization was successful, it returns a non-null context which + // can then be used for subsequent library calls.) + fame_context = fame_open(); + if(!fame_context) { + info->error("Unable to open FAME context, due to the following error: %s", strerror(errno)); + return; + } + + /* + typedef struct _fame_parameters_ { + int width; // width of the video sequence + int height; // height of the video sequence + char const *coding; // coding sequence + int quality; // video quality + int slices_per_frame; // number of slices per frame + unsigned int frames_per_sequence; // number of frames per sequence + int frame_rate_num; // numerator of frames per second + int frame_rate_den; // denominator of frames per second + unsigned int shape_quality; // binary shape quality + unsigned int search_range; // motion estimation search range + unsigned char verbose; // verbosity + } fame_parameters_t; + */ + // width and height specify the size of each frames of the video sequence. + // Both must be multiple of 16. width and height must be less than 4096x4096 + fame_par.width = 720; + fame_par.height = 576; + + // coding is a string of I, P or B characters representing the sequence of + // frames the encoder must produce. I frames are intra-coded frames (similar + // to JPEG), whereas P and B frames are motion compressed, respectively + // predicted from past reference (I or P) frame, or bidirectionally predicted + // from past and future reference frame. + fame_par.coding = config->readString("frame_sequence")->c_str(); + + // quality is a percentage, which controls compression versus quality. + fame_par.quality = config->readInt("video_quality"); + + // Bitrate + fame_par.bitrate = config->readInt("video_bitrate") * 1000; // video bitrate in bytes pr second (0=VBR) + + // slices_per_frame is the number of frame slices per frame. More slices provide + // better error recovery. There must be at least one slice per frame, and at most + // height / 16 + fame_par.slices_per_frame = 1;//fame_par.height / 16; + + // frames_per_sequence is the maximum number of frames contained in a video + // sequence. + fame_par.frames_per_sequence = 0xffffffff; // Unlimited length + + // frame_rate_num/frame_rate_den specify the number of frames per second for + // playback. + fame_par.frame_rate_num = 25; // 25 / 1 fps = 25 fps + fame_par.frame_rate_den = 1; + + // shape_quality is percentage determing the average binary shape accuracy in + // video with arbitrary shape. + fame_par.shape_quality = 100; // Original shape + + // search_range specifies the motion estimation search range in pixel unit. + // Small search ranges work best with slow motion videos, whereas larger search + // ranges are rather for fast motion videos. + fame_par.search_range = 0; // Adaptive search range + + // verbose when set to 1 outputs information on copyright, modules used and + // current frame on standard error. + fame_par.verbose = 0; + + static const char profilename[] = "MIaV\0"; + fame_par.profile = profilename; // profile name + fame_par.total_frames = 0; // total number of frames + + if(strcmp(config->readString("encoding_codec")->c_str(), "mpeg4") == 0) { + + info->info("Using mpeg4 compression."); + fame_object_t *object; + + object = fame_get_object(fame_context, "profile/mpeg4/simple"); + if(object) fame_register(fame_context, "profile", object); + + } else if(strcmp(config->readString("encoding_codec")->c_str(), "mpeg1") == 0) { + + info->info("Using mpeg1 compression."); + fame_object_t *object; + + object = fame_get_object(fame_context, "profile/mpeg1"); + if(object) fame_register(fame_context, "profile", object); + + } else if(strcmp(config->readString("encoding_codec")->c_str(), "mpeg1") == 0) { + } else { + info->info("Using default (mpeg1) compression."); + } + + fame_init(fame_context, &fame_par, fame_buffer, FAME_BUFFER_SIZE); +} + +LibFAMEWrapper::~LibFAMEWrapper() +{ + delete [] yuv.y; + delete [] yuv.u; + delete [] yuv.v; +} + +Frame *LibFAMEWrapper::encode(Frame *dvframe) +{ + // if(!f) return; // The file was not opened. + + // Decode DV Frame to YUV422 + int w = 720; + int h = 576; + + unsigned char *pixels[3]; + int pitches[3]; + + if(!dvdecoder) { + dvdecoder = dv_decoder_new(FALSE/*this value is unused*/, FALSE, FALSE); + dvdecoder->quality = DV_QUALITY_BEST; + + dv_parse_header(dvdecoder, dvframe->data); + //dv_parse_packs(decoder, frame->data); // Not needed anyway! + + dvdecoder->system = e_dv_system_625_50; // PAL lines, PAL framerate + dvdecoder->sampling = e_dv_sample_422; // 4 bytes y, 2 bytes u, 2 bytes v + dvdecoder->std = e_dv_std_iec_61834; + dvdecoder->num_dif_seqs = 12; + } + + pixels[ 0 ] = picture; // We use this as the output buffer + pitches[ 0 ] = w * 2; + + dv_decode_full_frame(dvdecoder, + dvframe->data, + e_dv_color_yuv, + pixels, + pitches); + + // Convert YUV422 to YUV420p + int w2 = w / 2; + uint8_t *y = yuv.y; + uint8_t *cb = yuv.u; + uint8_t *cr = yuv.v; + uint8_t *p = picture; + + for ( int i = 0; i < h; i += 2 ) { + // process two scanlines (one from each field, interleaved) + for ( int j = 0; j < w2; j++ ) { + // packed YUV 422 is: Y[i] U[i] Y[i+1] V[i] + *( y++ ) = *( p++ ); + *( cb++ ) = *( p++ ); + *( y++ ) = *( p++ ); + *( cr++ ) = *( p++ ); + } + + // process next two scanlines (one from each field, interleaved) + for ( int j = 0; j < w2; j++ ) { + // skip every second line for U and V + *( y++ ) = *( p++ ); + p++; + *( y++ ) = *( p++ ); + p++; + } + } + + // Allocate a new frame for the output + Frame *output = new Frame(NULL, FAME_BUFFER_SIZE); + + // Init frame params + dv_get_timestamp(dvdecoder, output->timecode); // Set timecode + output->size = 0; // Init size (incremented as we read) + unsigned char* pt = output->data; // Set pointer to start of data buffer + + // Encode YUV frame and write it to disk. + fame_start_frame(fame_context, &yuv, 0); + int written; + + while((written = fame_encode_slice(fame_context))) { + memcpy(pt, fame_buffer, written); + pt += written; + output->size += written; + } + + // fame_frame_statistics_t stats; + + // fame_end_frame(fame_context, &stats); + /* + info->info("frame_number: %d, coding: %c, target_bits: %d, actual_bits: %d, spatial_activity: %d, quant_scale: %f", + stats.frame_number, + stats.coding, + stats.target_bits, + stats.actual_bits, + stats.spatial_activity, + stats.quant_scale); + */ + /* + fame_frame_statistics_t_ { + unsigned int frame_number; + char coding; + signed int target_bits; + unsigned int actual_bits; + unsigned int spatial_activity; + float quant_scale; + } + */ + frame_number++; + calc_bitrate += output->size; //stats.actual_bits; + output->bitrate = (unsigned int)((double)calc_bitrate / (double)frame_number) * 25; + + return output; +} + |