/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*************************************************************************** * mov_encoder.cc * * Sat Feb 19 14:13:19 CET 2005 * Copyright 2005 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. */ /* * $Id$ */ /* * $Log$ * Revision 1.14 2005/05/07 10:56:18 deva * Changed print outs * * Revision 1.13 2005/05/07 10:25:34 deva * * Removed ffmpeg code from img_encoder and corrected decoding errors in mov_encoder * * Revision 1.12 2005/05/05 20:41:38 deva * * Removed the last pieces of ffmpeg... replaced it with libfame... * Not quite working yet, but all the major code is in place! * * Revision 1.11 2005/05/03 17:12:53 deva * Fixed a bug (forgot to set the frametime). * * Revision 1.10 2005/05/03 08:31:59 deva * Removed the error object, and replaced it with a more generic info object. * * Revision 1.9 2005/05/02 10:59:44 deva * Reverted to mpg file format (accidentally used avi with mpeg2) * * Revision 1.8 2005/05/01 09:56:26 deva * Added Id and Log tags to all files */ #include "mov_encoder.h" #include "debug.h" //av_alloc_format_context //av_destruct_packet_nofree MovEncoder::MovEncoder(const char *filename) { // FIXME: Hmmm... should this be detected somewhere?! static int w = 720; static int h = 576; // Initialize yuv strucutre. yuv.w = w; yuv.h = h; yuv.p = w; yuv.y = new unsigned char [w*h]; yuv.u = new unsigned char [w*h/4]; yuv.v = new unsigned char [w*h/4]; ////////////LIBDV STUFF/////////////// dvdecoder = NULL; // Initialize in encode method /////////LIBFAME STUFF/////////// // Allocate the output buffer. fame_buffer = new unsigned char [FAME_BUFFER_SIZE]; // Open output file f=fopen(filename, "wb"); // FIXME: check f == NULL // Open a new session of the fame library. fame_context = fame_open(); // FIXME: check fame_context == NULL // (If initialization was successful, it returns a non-null context which // can then be used for subsequent library calls.) /* 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. static const char coding[] = "I\0"; fame_par.coding = coding; // quality is a percentage, which controls compression versus quality. fame_par.quality = 100; // 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 = fame_par.height / 16; // frames_per_sequence is the maximum number of frames contained in a video // sequence. fame_par.frames_per_sequence = 1024;//25 * 60 * 60 * 2; // 25 fps in two hours. // 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; // 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 = 10; // FIXME: No idea what this should be!? // verbose when set to 1 outputs information on copyright, modules used and // current frame on standard error. fame_par.verbose = 1; fame_init(fame_context, &fame_par, fame_buffer, FAME_BUFFER_SIZE); // FIXME: fame_init return a new context, or NULL if an error occurred. } MovEncoder::~MovEncoder() { int written = fame_close(fame_context); fwrite(fame_buffer, written, 1, f); fclose(f); delete [] fame_buffer; delete [] yuv.y; delete [] yuv.u; delete [] yuv.v; } void MovEncoder::encode(Frame *dvframe) { encode_video(dvframe); encode_audio(dvframe); } #define _CLAMP(x) (unsigned char) ((x)<0?0:(((x)>255)?255:(x))) inline void rgb_to_yuv(unsigned char *rgb, unsigned char &y, unsigned char &u, unsigned char &v) { y = _CLAMP( 0.257 * rgb[0] + 0.504 * rgb[1] + 0.098 * rgb[2] + 16); v = _CLAMP( 0.439 * rgb[0] - 0.368 * rgb[1] - 0.071 * rgb[2] + 128); u = _CLAMP(-0.148 * rgb[0] - 0.291 * rgb[1] + 0.439 * rgb[2] + 128); } void MovEncoder::encode_video(Frame *dvframe) { // Decode DV Frame to YUV int w = 720; int h = 576; unsigned char rgb[720*576*4]; 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; 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; } dv_decode_full_frame(dvdecoder, dvframe->data, e_dv_color_rgb, pixels, pitches); /* e_dv_color_yuv, (uint8_t**) &yuv.y, //pixels, (int*) &yuv.w);//pitches); */ // cvt rgb to yuv for (int y=0; y