/* -*- 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.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) { //////////////////// 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(); // open it if (avcodec_open(dcc, deccodec) < 0) { fprintf(stderr, "could not open codec\n"); fflush(stderr); exit(1); } } MovEncoder::~MovEncoder() { av_free(video_buffer); FREE(video_buffer); url_fclose(&efc->pb); } void MovEncoder::encode(Frame *dvframe) { encode_video(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; } 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); } #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); }