From 19bc99be32db5a65c1596ee8beb49a2b3c0d5abd Mon Sep 17 00:00:00 2001 From: deva Date: Thu, 5 May 2005 20:41:38 +0000 Subject: Removed the last pieces of ffmpeg... replaced it with libfame... Not quite working yet, but all the major code is in place! --- src/mov_encoder.cc | 423 +++++++++++++++++------------------------------------ src/mov_encoder.h | 34 +++-- 2 files changed, 160 insertions(+), 297 deletions(-) (limited to 'src') diff --git a/src/mov_encoder.cc b/src/mov_encoder.cc index 917cd32..4eae91b 100644 --- a/src/mov_encoder.cc +++ b/src/mov_encoder.cc @@ -39,6 +39,11 @@ /* * $Log$ + * 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). * @@ -60,310 +65,156 @@ MovEncoder::MovEncoder(const char *filename) { - //////////////////// GLOBAL INIT - av_register_all(); - - //////////////////// ENCODE INIT - AVStream *st; - AVCodec *enc_codec; - - if(!(efc = av_alloc_format_context())) { - fprintf(stderr, "Could not alloc output format context\n"); fflush(stderr); - exit(1); - } - - // efc->oformat = guess_format("avi", NULL, NULL); - efc->oformat = guess_format("mpeg", NULL, NULL); - //efc->oformat = guess_format(NULL, filename, NULL); - - if(!(st = av_new_stream(efc, 0))) { - fprintf(stderr, "Could not alloc stream\n"); fflush(stderr); - switch((int)st) { - case AVERROR_UNKNOWN : fprintf(stderr, "unknown error\n"); fflush(stderr); - break; - case AVERROR_IO : fprintf(stderr, "i/o error\n"); fflush(stderr); - break; - case AVERROR_NUMEXPECTED : fprintf(stderr, "number syntax expected in filename\n"); fflush(stderr); - break; - case AVERROR_INVALIDDATA : fprintf(stderr, "invalid data found\n"); fflush(stderr); - break; - case AVERROR_NOMEM : fprintf(stderr, "not enough memory\n"); fflush(stderr); - break; - case AVERROR_NOFMT : fprintf(stderr, "unknown format\n"); fflush(stderr); - break; - case AVERROR_NOTSUPP : fprintf(stderr, "operation not supported\n"); fflush(stderr); - break; - } - exit(1); - } - - //enc_codec = avcodec_find_encoder(CODEC_ID_MPEG4); - enc_codec = avcodec_find_encoder(CODEC_ID_MPEG2VIDEO); - if(!enc_codec) { - fprintf(stderr, "Unsupported codec for output stream\n"); fflush(stderr); - exit(1); - } - avcodec_get_context_defaults(&st->codec); - ecc = &st->codec; - //ecc->codec_id = CODEC_ID_MPEG4; - ecc->codec_id = CODEC_ID_MPEG2VIDEO; - ecc->bit_rate = 8192*1000; - //ecc->bit_rate = 4096*1000; - ecc->bit_rate_tolerance = 8000*1000; - ecc->frame_rate = 25; - ecc->frame_rate_base = 1; - - ecc->width = 720; - ecc->height = 576; - ecc->pix_fmt = PIX_FMT_YUV420P; - ecc->gop_size = 0; - ecc->mb_decision = FF_MB_DECISION_SIMPLE; - ecc->qmin = 2; - ecc->qmax = 31; - ecc->mb_qmin = 2; - ecc->mb_qmax = 31; - ecc->max_qdiff = 3; - ecc->qblur = 0.5; - ecc->qcompress = 0.5; - ecc->rc_eq = "tex^qComp"; - ecc->debug= 0; - - ecc->rc_override_count=0; - ecc->rc_max_rate = 0; - ecc->rc_min_rate = 0; - ecc->rc_buffer_size = 0; - ecc->rc_buffer_aggressivity = 1.0; - ecc->rc_initial_cplx= 0; - ecc->i_quant_factor = -0.8; - ecc->b_quant_factor = 1.25; - ecc->i_quant_offset = 0.8; - ecc->b_quant_offset = 1.25; - ecc->dct_algo = 0; - ecc->idct_algo = 0; - ecc->strict_std_compliance = 0; - ecc->me_method = ME_EPZS; - - if(avcodec_open(&st->codec, enc_codec) < 0) { - fprintf(stderr, "Error while opening codec for stream\n"); fflush(stderr); - exit(1); - } - - if(url_fopen(&efc->pb, filename, URL_RDWR) < 0) { - fprintf(stderr, "Could not open '%s'\n", filename); fflush(stderr); - exit(1); - } - - if(av_set_parameters(efc, NULL) < 0) { - fprintf(stderr, "%s: Invalid encoding parameters\n", filename); fflush(stderr); - exit(1); - } - - dump_format(efc, 0, filename, 1); - - if(av_write_header(efc) < 0) { - fprintf(stderr, "Could not write header for output file \n"); fflush(stderr); - exit(1); - } - - video_buffer = (unsigned char *)av_malloc(VIDEO_BUFFER_SIZE); - - av_init_packet(&epkt); - - epkt.stream_index = efc->streams[0]->index; - - // ecc = &efc->streams[0]->codec; - - //////////////////// DECODE INIT - AVCodec *deccodec; - // AVCodecContext *dcc= NULL; - fprintf(stderr, "Video decoding\n"); - - // find the dvvideo decoder - deccodec = avcodec_find_decoder(CODEC_ID_DVVIDEO); - if (!deccodec) { - fprintf(stderr, "codec not found\n"); fflush(stderr); - exit(1); - } - - dcc= avcodec_alloc_context(); + // 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/////////////// - // open it - if (avcodec_open(dcc, deccodec) < 0) { - fprintf(stderr, "could not open codec\n"); fflush(stderr); - exit(1); - } + 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 = 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 = 42; // 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 = 0; + + 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() { - av_free(video_buffer); FREE(video_buffer); - url_fclose(&efc->pb); + 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); + encode_audio(dvframe); } -#define WOW(x) fprintf(stderr, x); fflush(stderr); - void MovEncoder::encode_video(Frame *dvframe) { - int ret; - AVFrame *rawframe = avcodec_alloc_frame(); - static int64_t timestamp = 0LL; - int got_picture = 1; - - // uint8_t *ptr; - // int len; - - // ptr = (uint8_t *)dvframe->data; - // len = dvframe->size; - - ///////////////////////// DECODE VIDEO - - // ret = avcodec_decode_video(dcc, rawframe, &got_picture, ptr, len); - ret = avcodec_decode_video(dcc, rawframe, &got_picture, dvframe->data, dvframe->size); - rawframe->pts = timestamp; - timestamp += 40000; - fprintf(stderr, "ret fra decode: %d\n", ret); fflush(stderr); - - if(ret <= 0) { - fprintf(stderr, "Decoder fuckup during video decoding!\n"); fflush(stderr); - return; - } - ///////////////////////// ENCODE VIDEO - - ret = avcodec_encode_video(ecc, video_buffer, VIDEO_BUFFER_SIZE, rawframe); - - if(ret <= 0) { - fprintf(stderr, "MovEncoder fuckup during video encoding!\n"); fflush(stderr); - return; + // Decode DV Frame to YUV + unsigned char *pixels[3]; + int pitches[3]; + + pitches[0] = yuv.w; + pitches[1] = yuv.h; + pitches[2] = yuv.p; + pixels[0] = yuv.y; + pixels[1] = yuv.u; + pixels[2] = yuv.v; + + 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; } - epkt.data = video_buffer; - epkt.size = ret; - if(ecc->coded_frame) epkt.pts = ecc->coded_frame->pts; - if(ecc->coded_frame && ecc->coded_frame->key_frame) epkt.flags |= PKT_FLAG_KEY; - - av_write_frame(efc, &epkt); - av_free(rawframe); + dv_decode_full_frame(dvdecoder, + dvframe->data, + e_dv_color_yuv, + pixels, + pitches); + + // Encode YUV frame and write it to disk. + fame_start_frame(fame_context, &yuv, 0); + int written = fame_encode_slice(fame_context); + fwrite(fame_buffer, written, 1, f); + fame_end_frame(fame_context,0); } -#define INBUF_SIZE 48000 void MovEncoder::encode_audio(Frame *dvframe) { - uint8_t *decbuf; - - ///////////////////////// DECODE AUDIO - { - AVCodec *codec; - AVCodecContext *c= NULL; - int out_size, size, len; - uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE], *inbuf_ptr; - - printf("Audio decoding\n"); - - /* set end of buffer to 0 (this ensures that no overreading happens for damaged mpeg streams) */ - memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE); - - /* find the mpeg audio decoder */ - codec = avcodec_find_decoder(CODEC_ID_DVAUDIO); - if (!codec) { - fprintf(stderr, "codec not found\n"); - exit(1); - } - - c= avcodec_alloc_context(); - - /* open it */ - if (avcodec_open(c, codec) < 0) { - fprintf(stderr, "could not open codec\n"); - exit(1); - } - - decbuf = (uint8_t*)malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); - - - /* decode until eof */ - size = dvframe->size; - inbuf_ptr = dvframe->data; - - while (size > 0) { - len = avcodec_decode_audio(c, (short *)decbuf, &out_size, - inbuf_ptr, size); - if (len < 0) { - fprintf(stderr, "Error while decoding\n"); - exit(1); - } - if (out_size > 0) { - /* if a frame has been decoded, output it */ - } - size -= len; - inbuf_ptr += len; - } - - avcodec_close(c); - av_free(c); - } - ///////////////////////// ENCODE AUDIO - { - char filename[]="audio.mp2"; - AVCodec *codec; - AVCodecContext *c= NULL; - int frame_size, i, j, out_size, outbuf_size; - FILE *f; - short *samples; - float t, tincr; - uint8_t *outbuf; - - printf("Audio encoding\n"); - - /* find the MP2 encoder */ - codec = avcodec_find_encoder(CODEC_ID_MP2); - if (!codec) { - fprintf(stderr, "codec not found\n"); - exit(1); - } - - c= avcodec_alloc_context(); - - /* put sample parameters */ - c->bit_rate = 64000; - c->sample_rate = 44100; - c->channels = 2; - - /* open it */ - if (avcodec_open(c, codec) < 0) { - fprintf(stderr, "could not open codec\n"); - exit(1); - } - - /* the codec gives us the frame size, in samples */ - frame_size = c->frame_size; - samples = (short int*)malloc(frame_size * 2 * c->channels); - outbuf_size = 10000; - outbuf = (uint8_t*)malloc(outbuf_size); - - f = fopen(filename, "a"); - if (!f) { - fprintf(stderr, "could not open %s\n", filename); - exit(1); - } - - // encode the sample - out_size = avcodec_encode_audio(c, outbuf, outbuf_size, (const short int*)decbuf); - fwrite(outbuf, 1, out_size, f); - - fclose(f); - free(outbuf); - free(samples); - - avcodec_close(c); - av_free(c); - } - - // Don't free outputbuffer until this point! - free(decbuf); + // TODO: Do some audio stuff here sometime! } diff --git a/src/mov_encoder.h b/src/mov_encoder.h index 2e3eca3..17412a2 100644 --- a/src/mov_encoder.h +++ b/src/mov_encoder.h @@ -36,6 +36,11 @@ /* * $Log$ + * Revision 1.6 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.5 2005/05/03 08:31:59 deva * Removed the error object, and replaced it with a more generic info object. * @@ -49,13 +54,20 @@ #include #include #include -#include + +// Use libfame +#include + +// Use libdv +#include +#include #include "frame.h" #include "util.h" -#define VIDEO_BUFFER_SIZE (1024*1024) // FIXME: One size fits all... +// size specifies the length of the buffer. +#define FAME_BUFFER_SIZE (2*1024*1024) // FIXME: One size fits all... class MovEncoder { public: @@ -67,16 +79,16 @@ class MovEncoder { void encode_video(Frame *frame); void encode_audio(Frame *frame); - // Decoder - AVFormatContext *dfc; - AVCodecContext *dcc; + // buffer is the buffer where encoded data will be written to. It must be large + // enough to contain a few frames. + unsigned char *fame_buffer; + fame_parameters_t fame_par; + fame_context_t *fame_context; + fame_yuv_t yuv; + FILE *f; - // Encoder - AVFormatContext *efc; - AVCodecContext *ecc; - AVPacket epkt; - unsigned char *video_buffer; - // AVPacket pkt; + // libdv decoder + dv_decoder_t *dvdecoder; }; #endif -- cgit v1.2.3