Created
February 5, 2014 18:46
-
-
Save pauldotknopf/8830397 to your computer and use it in GitHub Desktop.
FFMpegHelper.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "stdafx.h" | |
#include "FFMpegHelper.h" | |
#include "get_extradata.h" | |
#include <iostream> | |
FFMpegHelper::FFMpegHelper(void) | |
{ | |
} | |
FFMpegHelper::~FFMpegHelper(void) | |
{ | |
} | |
AVStream *FFMpegHelper::add_audio_stream (AVFormatContext *oc, int codec_id) | |
{ | |
AVCodecContext * c; | |
AVStream * st; | |
st = av_new_stream (oc , 1); | |
if (! st) { | |
fprintf( stderr, "Could not alloc stream\n" ); | |
exit(1); | |
} | |
c = st->codec; | |
c->codec_id = (AVCodecID)codec_id; | |
c->codec_type = AVMEDIA_TYPE_AUDIO ; | |
/* put sample parameters */ | |
c->sample_fmt = AV_SAMPLE_FMT_S16; | |
c->sample_rate = 48000; | |
c->channels = 2; | |
c->bit_rate = 448000; //in bits/sec //@@@@@@@@@@@@@@@@@@@@ this can be customized @@@@@@@@@@@@@@@@@@@@ | |
c->profile = FF_PROFILE_AAC_LOW; //@@@@@@@@@@@@@@@@@@@@ this can be customized @@@@@@@@@@@@@@@@@@@@ | |
c->channel_layout = AV_CH_LAYOUT_STEREO;//?????? what is this????? | |
// some formats want stream headers to be separate | |
if(! strcmp( oc->oformat-> name, "mp4" ) || !strcmp (oc ->oformat ->name , "mov" ) || !strcmp (oc ->oformat ->name , "3gp" )) | |
c->flags |= CODEC_FLAG_GLOBAL_HEADER ; | |
return st; | |
} | |
void FFMpegHelper::open_audio (AVFormatContext *oc, AVStream *st) | |
{ | |
AVCodecContext * c; | |
AVCodec * codec; | |
c = st-> codec; | |
/* find the audio encoder */ | |
//codec = avcodec_find_encoder(c ->codec_id); | |
codec = avcodec_find_encoder_by_name("libfdk_aac"); | |
if (! codec) { | |
fprintf( stderr, "codec not found\n" ); | |
exit(1); | |
} | |
/* open it */ | |
if ( avcodec_open2( c, codec, NULL) < 0) { | |
fprintf( stderr, "could not open audio codec\n" ); | |
exit(1); | |
} | |
} | |
int FFMpegHelper::init_ffmpeg(mux_ctx_t *pMux_ctx, int VidWidth, int VidHeight, double frame_rate, int profile, int level, bool useAudio) | |
{ | |
/* initialize libavcodec, and register all codecs and formats */ | |
av_register_all(); | |
/* auto detect the output format from the name. default is mpeg. */ | |
pMux_ctx->fmt = av_guess_format (NULL , pMux_ctx->filename , NULL ); | |
if (! pMux_ctx->fmt) { | |
printf( "Could not deduce output format from file extension: using MPEG.\n"); | |
pMux_ctx->fmt = av_guess_format ("mpeg" , NULL , NULL ); | |
} | |
if (! pMux_ctx->fmt) { | |
fprintf( stderr, "Could not find suitable output format\n" ); | |
exit(1); | |
} | |
/* allocate the output media context */ | |
pMux_ctx->oc = avformat_alloc_context (); | |
if (! pMux_ctx->oc) { | |
fprintf( stderr, "Memory error\n" ); | |
exit(1); | |
} | |
pMux_ctx->oc->oformat = pMux_ctx->fmt; | |
printf("#####################################################\n"); | |
printf("%s\n", avformat_license()); | |
pMux_ctx->fmt->video_codec = AV_CODEC_ID_H264; | |
if(useAudio){ | |
pMux_ctx->fmt->audio_codec = AV_CODEC_ID_AAC; | |
}else | |
{ | |
pMux_ctx->fmt->audio_codec = AV_CODEC_ID_NONE; | |
} | |
_snprintf( pMux_ctx->oc->filename, sizeof( pMux_ctx->oc->filename), "%s" , pMux_ctx->filename ); | |
/* add the audio and video streams using the default format codecs | |
and initialize the codecs */ | |
pMux_ctx->video_st = NULL; | |
if ( pMux_ctx->fmt->video_codec != CODEC_ID_NONE ) | |
{ | |
AVCodecContext * c; | |
pMux_ctx->video_st = av_new_stream (pMux_ctx->oc , 0); | |
if (! pMux_ctx->video_st) | |
{ | |
fprintf( stderr, "Could not alloc video_stream\n" ); | |
exit(1); | |
} | |
c = pMux_ctx->video_st->codec; | |
c->codec_id = ( AVCodecID) pMux_ctx->fmt->video_codec; | |
c->codec_type = AVMEDIA_TYPE_VIDEO ; | |
c->me_range = 2048; | |
c->max_qdiff = 51; | |
/* resolution muvideo_st be a multiple of two */ | |
c->width = VidWidth; | |
c->height = VidHeight; | |
c->time_base.num = 1000000; | |
c->time_base.den = 1000000*(int)frame_rate; | |
c->pix_fmt = AV_PIX_FMT_YUV420P ; | |
//############################# | |
c->extradata = (uint8_t*)av_mallocz(100);//100bytes must be plenty for extradata | |
encFrame_t encFrame; | |
encFrame.frame_height = VidHeight; | |
encFrame.frame_width = VidWidth; | |
encFrame.useHighProfile = profile == 2; | |
encFrame.level = level; | |
encFrame.PQIndex = 10;//junk start qp | |
get_extradata((char *)c->extradata, &c->extradata_size, &encFrame); | |
//############################# | |
if ( c->codec_id == CODEC_ID_MPEG2VIDEO ) { | |
/* juvideo_st for tevideo_sting, we also add B frames */ | |
c->max_b_frames = 2; | |
} | |
if ( c->codec_id == CODEC_ID_MPEG1VIDEO ){ | |
/* Needed to avoid using macroblocks in which some coeffs overflow. | |
This does not happen with normal video, it juvideo_st happens here as | |
the motion of the chroma plane does not match the luma plane. */ | |
c->mb_decision =2; | |
} | |
// some formats want video_stream headers to be separate | |
if(! strcmp( pMux_ctx->oc->oformat-> name, "mp4" ) || !strcmp (pMux_ctx->oc ->oformat ->name , "mov" ) || !strcmp (pMux_ctx->oc ->oformat ->name , "3gp" )) | |
c->flags |= CODEC_FLAG_GLOBAL_HEADER ; | |
} | |
/* now that all the parameters are set, we can open the audio and | |
video codecs and allocate the necessary encode buffers */ | |
//if ( pMux_ctx->video_st) | |
if(0) | |
{ | |
AVCodec * codec; | |
/* find the video encoder */ | |
codec = avcodec_find_encoder (pMux_ctx->video_st->codec->codec_id ); | |
if (! codec) { | |
fprintf( stderr, "Video codec not found\n" ); | |
exit(1); | |
} | |
/* open the codec */ | |
if ( avcodec_open2( pMux_ctx->video_st->codec, codec, NULL) < 0) { | |
fprintf( stderr, "could not open video codec\n" ); | |
exit(1); | |
} | |
} | |
/* open the output file */ | |
if (!( pMux_ctx->fmt-> flags & AVFMT_NOFILE )) { | |
if ( avio_open(&pMux_ctx->oc->pb, pMux_ctx->filename, AVIO_FLAG_WRITE) < 0) { | |
fprintf( stderr, "Could not open '%s'\n" , pMux_ctx->filename ); | |
exit(1); | |
} | |
} | |
if ( pMux_ctx->fmt->audio_codec != CODEC_ID_NONE ) | |
{ | |
pMux_ctx->audio_st = add_audio_stream (pMux_ctx->oc, pMux_ctx->fmt->audio_codec ); | |
pMux_ctx->audio_outbuf_size = FF_MIN_BUFFER_SIZE * 10; | |
pMux_ctx->audio_outbuf = (uint8_t *)av_malloc(pMux_ctx->audio_outbuf_size); | |
} | |
if ( pMux_ctx->audio_st) | |
{ | |
open_audio( pMux_ctx->oc, pMux_ctx->audio_st); | |
} | |
/* write the stream header, if any */ | |
if( avformat_write_header (pMux_ctx->oc, NULL ) < 0) | |
{ | |
fprintf( stderr, "Could not write header for output file\n" ); | |
return -1; | |
} | |
return 0; | |
} | |
int FFMpegHelper::close_ffmpeg(mux_ctx_t *pMux_ctx) | |
{ | |
int i; | |
/* close each codec */ | |
if ( pMux_ctx->video_st) | |
{ | |
avcodec_close( pMux_ctx->video_st->codec); | |
} | |
if ( pMux_ctx->audio_st) | |
{ | |
avcodec_close( pMux_ctx->audio_st->codec); | |
av_free( pMux_ctx->audio_outbuf ); | |
} | |
/* write the trailer, if any */ | |
int res = av_write_trailer (pMux_ctx->oc ); | |
/* free the streams */ | |
for( i = 0; i < (int)pMux_ctx->oc->nb_streams; i++) { | |
av_freep(& pMux_ctx->oc->streams[ i]-> codec); | |
av_freep(& pMux_ctx->oc->streams[ i]); | |
} | |
if (!( pMux_ctx->fmt-> flags & AVFMT_NOFILE )) { | |
/* close the output file */ | |
avio_close( pMux_ctx->oc->pb); | |
} | |
/* free the stream */ | |
av_free( pMux_ctx->oc); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment