summaryrefslogtreecommitdiff
path: root/server/libfame_wrapper.cc
diff options
context:
space:
mode:
Diffstat (limited to 'server/libfame_wrapper.cc')
-rw-r--r--server/libfame_wrapper.cc273
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;
+}
+