int FFMPEG_Wrapper::init(int input_width, int input_height, const ServerConfiguration& config) { boost::mutex::scoped_lock lock(frame_mutex_); time_started_ = boost::posix_time::microsec_clock::local_time(); config_ = config; input_width_ = input_width; input_height_ = input_height; output_width_ = config.frame_width_; output_height_ = config.frame_height_; if (output_width_<0) output_width_ = input_width_; if (output_height_<0) output_height_ = input_height_; av_lockmgr_register(&ff_lockmgr); /* register all the codecs */ avcodec_register_all(); av_register_all(); // lookup webm codec avformat_alloc_output_context2(&ffmpeg_format_context_, NULL, config_.codec_.c_str(), NULL); if (!ffmpeg_format_context_) { return -1; } ffmpeg_output_format_ = ffmpeg_format_context_->oformat; /* Add the audio and video streams using the default format codecs * and initialize the codecs. */ ffmpeg_video_st_ = NULL; if (ffmpeg_output_format_->video_codec != AV_CODEC_ID_NONE) { /* find the video encoder */ ffmpeg_codec_ = avcodec_find_encoder(ffmpeg_output_format_->video_codec); if (!(ffmpeg_codec_)) { fprintf(stderr, "Codec not found (%s)\n",config_.codec_.c_str()); return -1; } ffmpeg_video_st_ = avformat_new_stream(ffmpeg_format_context_, ffmpeg_codec_); if (!ffmpeg_video_st_) { fprintf(stderr, "Could not alloc stream\n"); return -1; } ffmpeg_codec_context_ = ffmpeg_video_st_->codec; avcodec_get_context_defaults3(ffmpeg_codec_context_, ffmpeg_codec_); ////////////////////////////////////////////// // ffmpeg codec configuration ////////////////////////////////////////////// ffmpeg_codec_context_->codec_id = ffmpeg_output_format_->video_codec; ffmpeg_codec_context_->bit_rate = config_.bitrate_; ffmpeg_codec_context_->width = output_width_; ffmpeg_codec_context_->height = output_height_; ffmpeg_codec_context_->delay = 0; ffmpeg_codec_context_->time_base.den = config_.framerate_+3; //increased framerate to compensate playback delay ffmpeg_codec_context_->time_base.num = 1; ffmpeg_codec_context_->gop_size = config_.gop_; /* emit one intra ffmpeg_frame_ every twelve frames at most */ ffmpeg_codec_context_->pix_fmt = PIX_FMT_YUV420P; ffmpeg_codec_context_->max_b_frames = 0; av_opt_set(ffmpeg_codec_context_->priv_data, "quality", config_.profile_.c_str(), 0); av_opt_set(ffmpeg_codec_context_->priv_data, "deadline", "1", 0); av_opt_set(ffmpeg_codec_context_->priv_data, "auto-alt-ref", "0", 0); // lag in frames av_opt_set(ffmpeg_codec_context_->priv_data, "lag-in-frames", "1", 0); av_opt_set(ffmpeg_codec_context_->priv_data, "rc_lookahead", "1", 0); av_opt_set(ffmpeg_codec_context_->priv_data, "drop_frame", "1", 0); // enable error-resilient coding av_opt_set(ffmpeg_codec_context_->priv_data, "error-resilient", "1", 0); // buffer size of rate controller (length: rc_buffer_size/bitrate * 1000) ms int bufsize = 10;//ffmpeg_codec_context_->bit_rate/10; ffmpeg_codec_context_->rc_buffer_size = bufsize; // prebuffering at decoder ffmpeg_codec_context_->rc_initial_buffer_occupancy = bufsize ;//bitrate/3; av_opt_set_int(ffmpeg_codec_context_->priv_data, "bufsize", bufsize, 0); av_opt_set_int(ffmpeg_codec_context_->priv_data, "buf-initial", bufsize, 0); av_opt_set_int(ffmpeg_codec_context_->priv_data, "buf-optimal", bufsize, 0); // buffer agressivity ffmpeg_codec_context_->rc_buffer_aggressivity = 0.5; // Quality settings //ffmpeg_codec_context_->qmin = 50; //ffmpeg_codec_context_->qmax = 62; if (config_.quality_>0) ffmpeg_codec_context_->qmin = config_.quality_; //ffmpeg_codec_context_->frame_skip_threshold = 100; /* Some formats want stream headers to be separate. */ if (ffmpeg_format_context_->oformat->flags & AVFMT_GLOBALHEADER) ffmpeg_codec_context_->flags |= CODEC_FLAG_GLOBAL_HEADER; } if (ffmpeg_video_st_) { int ret; /* open the codec */ { boost::mutex::scoped_lock lock(codec_mutex_); if (avcodec_open2(ffmpeg_codec_context_, ffmpeg_codec_, NULL) < 0) { fprintf(stderr, "Could not open video codec\n"); return -1; } } /* allocate and init a re-usable ffmpeg_frame_ */ ffmpeg_frame_ = avcodec_alloc_frame(); if (!ffmpeg_frame_) { fprintf(stderr, "Could not allocate video ffmpeg_frame_\n"); return -1; } /* Allocate the encoded raw picture. */ ret = avpicture_alloc(ffmpeg_dst_picture_, ffmpeg_codec_context_->pix_fmt, output_width_, output_height_); if (ret < 0) { fprintf(stderr, "Could not allocate picture\n"); return -1; } /* If the output format is not YUV420P, then a temporary YUV420P * picture is needed too. It is then converted to the required * output format. */ ret = avpicture_alloc(ffmpeg_src_picture_, AV_PIX_FMT_RGB24, input_width_, input_height_); if (ret < 0) { fprintf(stderr, "Could not allocate temporary picture\n"); return -1; } /* copy data and linesize picture pointers to ffmpeg_frame_ */ *((AVPicture *)ffmpeg_frame_) = *ffmpeg_dst_picture_; av_dump_format(ffmpeg_format_context_, 0, "", 1); ffmpeg_output_format_->flags |= AVFMT_NOFILE; if (ffmpeg_frame_) ffmpeg_frame_->pts = 0; } init_ = true; return 0; }
/** \fn saveAsJpg \brief save current image into filename, into jpg format */ bool ADMImage::saveAsJpg(const char *filename) { AVCodecContext *context=NULL; AVFrame frame; bool result=false; AVCodec *codec=NULL; int sz=0,r=0; ADM_byteBuffer byteBuffer; context=avcodec_alloc_context(); if(!context) { printf("[saveAsJpg] Cannot allocate context\n"); return false; } codec=avcodec_find_encoder(CODEC_ID_MJPEG); if(!codec) { printf("[saveAsJpg] Cannot allocate codec\n"); goto jpgCleanup; } context->pix_fmt =PIX_FMT_YUV420P; context->strict_std_compliance = -1; context->time_base.den=1; context->time_base.num=1; context->width=_width; context->height=_height; context->flags |= CODEC_FLAG_QSCALE; r=avcodec_open(context, codec); if(r<0) { printf("[saveAsJpg] Cannot mix codec and context\n"); ADM_dealloc (context); return false; } // Setup our image & stuff.... frame.linesize[0] = GetPitch(PLANAR_Y); frame.linesize[1] = GetPitch(PLANAR_U); frame.linesize[2] = GetPitch(PLANAR_V); frame.data[0] = GetWritePtr(PLANAR_Y); frame.data[2] = GetWritePtr(PLANAR_U); frame.data[1] = GetWritePtr(PLANAR_V); // Grab a temp buffer // Encode! frame.quality = (int) floor (FF_QP2LAMBDA * 2+ 0.5); byteBuffer.setSize(_width*_height*4); if ((sz = avcodec_encode_video (context, byteBuffer.at(0), _width*_height*4, &frame)) < 0) { printf("[jpeg] Error %d encoding video\n",sz); goto jpgCleanup; } // Ok now write our file... { FILE *f=ADM_fopen(filename,"wb"); if(f) { fwrite(byteBuffer.at(0),sz,1,f); fclose(f); result=true; }else { printf("[saveAsJpeg] Cannot open %s for writing!\n",filename); } } // Cleanup jpgCleanup: if(context) { avcodec_close (context); av_free (context); } context=NULL; return result; }
bool FFMpegVideoEncoder::openVideoEncoder(const VideoEncoderParam& param) { encodeParam = param; AVCodecID codecID; switch(param.codec) { case CodecType::H264: codecID = CODEC_ID_H264; break; case CodecType::MPEG4: codecID = CODEC_ID_MPEG4; break; default: codecID = CODEC_ID_MPEG4; break; } codec = avcodec_find_encoder(codecID); codecCtx = avcodec_alloc_context3(codec); codecCtx->gop_size = param.gop; codecCtx->max_b_frames = param.bframe; codecCtx->width = param.width; codecCtx->height = param.height; codecCtx->time_base.num = param.fpsDen; codecCtx->time_base.den = param.fpsNum; codecCtx->pix_fmt = param.colorSpace; codecCtx->bit_rate = param.bitrate * 1000; codecCtx->bit_rate_tolerance = codecCtx->bit_rate + codecCtx->bit_rate /100; codecCtx->delay = 0; //codecCtx->coder_type = 0; //codecCtx->me_cmp |= 1; //codecCtx->me_method = ME_HEX; //codecCtx->me_subpel_quality = 0; //codecCtx->me_range = 16; //codecCtx->scenechange_threshold = 40; //codecCtx->i_quant_factor = 0.71; //codecCtx->b_frame_strategy = 1; //codecCtx->qcompress = 0.5; //codecCtx->qmin = 2; //codecCtx->qmax = 31; //codecCtx->max_qdiff = 4; //codecCtx->refs = 3; //codecCtx->trellis = 1; //codecCtx->chromaoffset = 0; //codecCtx->thread_count = 1; int error = avcodec_open2(codecCtx, codec, NULL); if (error < 0) { std::cout << "Open video encoder failed" << std::endl; } pic = av_frame_alloc(); pic->width = param.width; pic->height = param.height; pic->format = param.colorSpace; avpicture_alloc((AVPicture*)pic, AV_PIX_FMT_YUV420P, pic->width, pic->height); convertCtx = sws_getContext(param.width, param.height, PIX_FMT_RGB24, param.width, param.height, PIX_FMT_YUV420P, SWS_FAST_BILINEAR, NULL, NULL, NULL); return true; }
// Convert Java types const jbyte *native_filename1, *native_filename2; native_filename1 = (*env)->GetStringUTFChars(env, filename1, NULL); native_filename2 = (*env)->GetStringUTFChars(env, filename2, NULL); int native_height = (int) height; int native_width = (int) width; avcodec_register_all(); int codec_id = CODEC_ID_MPEG1VIDEO; LOGI("Encode video file %s", native_filename1); /* find the mpeg1 video encoder */ codec = avcodec_find_encoder(codec_id); if (!codec) { //fprintf(stderr, "codec not found\n"); LOGI("codec not found"); exit(1); } c = avcodec_alloc_context3(codec); frame= avcodec_alloc_frame(); LOGI("alloc AVFrame and AVCodecContext"); /* put sample parameters */ c->bit_rate = 400000; /* resolution must be a multiple of two */ c->width = native_width;
static int encavcodecaInit(hb_work_object_t *w, hb_job_t *job) { AVCodec *codec; AVCodecContext *context; hb_audio_t *audio = w->audio; hb_work_private_t *pv = calloc(1, sizeof(hb_work_private_t)); w->private_data = pv; pv->job = job; pv->list = hb_list_init(); // channel count, layout and matrix encoding int matrix_encoding; uint64_t channel_layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, &matrix_encoding); pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown); // default settings and options AVDictionary *av_opts = NULL; const char *codec_name = NULL; enum AVCodecID codec_id = AV_CODEC_ID_NONE; enum AVSampleFormat sample_fmt = AV_SAMPLE_FMT_FLTP; int bits_per_raw_sample = 0; int profile = FF_PROFILE_UNKNOWN; // override with encoder-specific values switch (audio->config.out.codec) { case HB_ACODEC_AC3: codec_id = AV_CODEC_ID_AC3; if (matrix_encoding != AV_MATRIX_ENCODING_NONE) av_dict_set(&av_opts, "dsur_mode", "on", 0); break; case HB_ACODEC_FFEAC3: codec_id = AV_CODEC_ID_EAC3; if (matrix_encoding != AV_MATRIX_ENCODING_NONE) av_dict_set(&av_opts, "dsur_mode", "on", 0); break; case HB_ACODEC_FDK_AAC: case HB_ACODEC_FDK_HAAC: codec_name = "libfdk_aac"; sample_fmt = AV_SAMPLE_FMT_S16; bits_per_raw_sample = 16; switch (audio->config.out.codec) { case HB_ACODEC_FDK_HAAC: profile = FF_PROFILE_AAC_HE; break; default: profile = FF_PROFILE_AAC_LOW; break; } // Libav's libfdk-aac wrapper expects back channels for 5.1 // audio, and will error out unless we translate the layout if (channel_layout == AV_CH_LAYOUT_5POINT1) channel_layout = AV_CH_LAYOUT_5POINT1_BACK; break; case HB_ACODEC_FFAAC: codec_name = "aac"; av_dict_set(&av_opts, "stereo_mode", "ms_off", 0); break; case HB_ACODEC_FFFLAC: case HB_ACODEC_FFFLAC24: codec_id = AV_CODEC_ID_FLAC; switch (audio->config.out.codec) { case HB_ACODEC_FFFLAC24: sample_fmt = AV_SAMPLE_FMT_S32; bits_per_raw_sample = 24; break; default: sample_fmt = AV_SAMPLE_FMT_S16; bits_per_raw_sample = 16; break; } break; default: hb_error("encavcodecaInit: unsupported codec (0x%x)", audio->config.out.codec); return 1; } if (codec_name != NULL) { codec = avcodec_find_encoder_by_name(codec_name); if (codec == NULL) { hb_error("encavcodecaInit: avcodec_find_encoder_by_name(%s) failed", codec_name); return 1; } } else { codec = avcodec_find_encoder(codec_id); if (codec == NULL) { hb_error("encavcodecaInit: avcodec_find_encoder(%d) failed", codec_id); return 1; } } // allocate the context and apply the settings context = avcodec_alloc_context3(codec); hb_ff_set_sample_fmt(context, codec, sample_fmt); context->bits_per_raw_sample = bits_per_raw_sample; context->profile = profile; context->channel_layout = channel_layout; context->channels = pv->out_discrete_channels; context->sample_rate = audio->config.out.samplerate; if (audio->config.out.bitrate > 0) { context->bit_rate = audio->config.out.bitrate * 1000; } else if (audio->config.out.quality >= 0) { context->global_quality = audio->config.out.quality * FF_QP2LAMBDA; context->flags |= CODEC_FLAG_QSCALE; if (audio->config.out.codec == HB_ACODEC_FDK_AAC || audio->config.out.codec == HB_ACODEC_FDK_HAAC) { char vbr[2]; snprintf(vbr, 2, "%.1g", audio->config.out.quality); av_dict_set(&av_opts, "vbr", vbr, 0); } } if (audio->config.out.compression_level >= 0) { context->compression_level = audio->config.out.compression_level; } // For some codecs, libav requires the following flag to be set // so that it fills extradata with global header information. // If this flag is not set, it inserts the data into each // packet instead. context->flags |= CODEC_FLAG_GLOBAL_HEADER; if (hb_avcodec_open(context, codec, &av_opts, 0)) { hb_error("encavcodecaInit: hb_avcodec_open() failed"); return 1; } // avcodec_open populates the opts dictionary with the // things it didn't recognize. AVDictionaryEntry *t = NULL; while ((t = av_dict_get(av_opts, "", t, AV_DICT_IGNORE_SUFFIX))) { hb_log("encavcodecaInit: Unknown avcodec option %s", t->key); } av_dict_free(&av_opts); pv->context = context; audio->config.out.samples_per_frame = pv->samples_per_frame = context->frame_size; pv->input_samples = context->frame_size * context->channels; pv->input_buf = malloc(pv->input_samples * sizeof(float)); // Some encoders in libav (e.g. fdk-aac) fail if the output buffer // size is not some minumum value. 8K seems to be enough :( pv->max_output_bytes = MAX(FF_MIN_BUFFER_SIZE, (pv->input_samples * av_get_bytes_per_sample(context->sample_fmt))); // sample_fmt conversion if (context->sample_fmt != AV_SAMPLE_FMT_FLT) { pv->output_buf = malloc(pv->max_output_bytes); pv->avresample = avresample_alloc_context(); if (pv->avresample == NULL) { hb_error("encavcodecaInit: avresample_alloc_context() failed"); return 1; } av_opt_set_int(pv->avresample, "in_sample_fmt", AV_SAMPLE_FMT_FLT, 0); av_opt_set_int(pv->avresample, "out_sample_fmt", context->sample_fmt, 0); av_opt_set_int(pv->avresample, "in_channel_layout", context->channel_layout, 0); av_opt_set_int(pv->avresample, "out_channel_layout", context->channel_layout, 0); if (hb_audio_dither_is_supported(audio->config.out.codec)) { // dithering needs the sample rate av_opt_set_int(pv->avresample, "in_sample_rate", context->sample_rate, 0); av_opt_set_int(pv->avresample, "out_sample_rate", context->sample_rate, 0); av_opt_set_int(pv->avresample, "dither_method", audio->config.out.dither_method, 0); } if (avresample_open(pv->avresample)) { hb_error("encavcodecaInit: avresample_open() failed"); avresample_free(&pv->avresample); return 1; } } else { pv->avresample = NULL; pv->output_buf = pv->input_buf; } if (context->extradata != NULL) { memcpy(w->config->extradata.bytes, context->extradata, context->extradata_size); w->config->extradata.length = context->extradata_size; } audio->config.out.delay = av_rescale_q(context->delay, context->time_base, (AVRational){1, 90000}); return 0; }
int CFfmpeg::Open(const char* pszUrl) { unsigned int i; m_sUrl = pszUrl; m_sUrl.erase(0, strlen("ffmpeg://")); //+ infmt_ctx = avformat_alloc_context(); //ring_buffer_write(&cbuffer.ringbuffer, inputbuffer, sizeof(inputbuffer)); //unsigned char* inputbuffer = NULL; //inputbuffer = (unsigned char*)malloc(MAIN_BUFFER_SIZE); init_put_byte(&inputpb, inputbuffer, MAIN_BUFFER_SIZE, 0, &cbuffer, i_read_data, NULL, i_seek_data ); //inputpb.buf_end = inputpb.buf_ptr; infmt_ctx->pb = &inputpb; //av_read_frame(infmt_ctx, &pkt); //+ avformat_open_input(&infmt_ctx, m_sUrl.c_str(), NULL, NULL); if(!infmt_ctx) { FFMPEG_ERROR("unknown url: %s", pszUrl); return -1; } av_find_stream_info(infmt_ctx); av_dump_format(infmt_ctx, 0, m_sUrl.c_str(), 0); filesize = avio_size(infmt_ctx->pb); printf("filesize = %d\n", filesize); check_transcode(); if(!transcode) { if(infmt_ctx) { av_close_input_file(infmt_ctx); infmt_ctx = NULL; } m_pFp = fopen(m_sUrl.c_str(), "rb"); if(!m_pFp) { //perror("fopen"); FFMPEG_ERROR("error fopen: %s", strerror(errno)); return -1; } } else { FFMPEG_DEBUG("transcode or remux"); avformat_alloc_output_context2(&oc, NULL, "mpegts", NULL); unsigned int pid = 0x100; for(i=0; i<infmt_ctx->nb_streams; i++) { AVStream *stream = infmt_ctx->streams[i]; if(stream->codec->codec_type==AVMEDIA_TYPE_VIDEO && video==-1) { video = i; FFMPEG_DEBUG("video index: %d, pid: 0x%x", i, pid++); vst = av_new_stream(oc, 0); avcodec_copy_context(vst->codec, infmt_ctx->streams[video]->codec); //vst->codec->time_base = infmt_ctx->streams[video]->time_base; vst->codec->sample_aspect_ratio = vst->sample_aspect_ratio = infmt_ctx->streams[video]->codec->sample_aspect_ratio; vst->stream_copy = 1; vst->avg_frame_rate = infmt_ctx->streams[video]->avg_frame_rate; vst->discard = AVDISCARD_NONE; vst->disposition = infmt_ctx->streams[video]->disposition; vst->duration = infmt_ctx->streams[video]->duration; vst->first_dts = infmt_ctx->streams[video]->first_dts; vst->r_frame_rate = infmt_ctx->streams[video]->r_frame_rate; vst->time_base = infmt_ctx->streams[video]->time_base; vst->quality = infmt_ctx->streams[video]->quality; vst->start_time = infmt_ctx->streams[video]->start_time; } else if(stream->codec->codec_type==AVMEDIA_TYPE_AUDIO && audio1==-1) { audio1 = i; FFMPEG_DEBUG("audio1 index: %d, pid: 0x%x", i, pid++); ast1 = av_new_stream(oc, 0); if(stream->codec->codec_id == CODEC_ID_AC3 || stream->codec->codec_id == CODEC_ID_DTS || stream->codec->codec_id == CODEC_ID_PCM_S16BE || stream->codec->codec_id == CODEC_ID_PCM_S16LE) { acodec1 = stream->codec; AVCodec *inAcodec = avcodec_find_decoder(stream->codec->codec_id); avcodec_open(stream->codec, inAcodec); AVCodec *outAcodec = avcodec_find_encoder(CODEC_ID_MP2); //ast1->codec = avcodec_alloc_context3(outAcodec); ast1->codec->bit_rate = 128000; ast1->codec->sample_rate = stream->codec->sample_rate; if(stream->codec->channels > 2) { stream->codec->request_channels = 2; } ast1->codec->channels = 2; ast1->codec->sample_fmt = AV_SAMPLE_FMT_S16; avcodec_open(ast1->codec, outAcodec); ast1->codec->time_base = infmt_ctx->streams[audio1]->time_base; ring_buffer_init(&adecrbuffer1, 524288); } else { avcodec_copy_context(ast1->codec, infmt_ctx->streams[audio1]->codec); //ast1->codec->time_base = infmt_ctx->streams[audio1]->time_base; ast1->stream_copy = 1; ast1->first_dts = infmt_ctx->streams[audio1]->first_dts; ast1->r_frame_rate = infmt_ctx->streams[audio1]->r_frame_rate; ast1->time_base = infmt_ctx->streams[audio1]->time_base; ast1->quality = infmt_ctx->streams[audio1]->quality; ast1->start_time = infmt_ctx->streams[audio1]->start_time; ast1->duration = infmt_ctx->streams[audio1]->duration; } } else if(stream->codec->codec_type==AVMEDIA_TYPE_AUDIO && audio1!=i && audio2==-1) { audio2 = i; FFMPEG_DEBUG("audio2 index: %d, pid: 0x%x", i, pid++); ast2 = av_new_stream(oc, 0); if(stream->codec->codec_id == CODEC_ID_AC3 || stream->codec->codec_id == CODEC_ID_DTS || stream->codec->codec_id == CODEC_ID_PCM_S16BE || stream->codec->codec_id == CODEC_ID_PCM_S16LE) { acodec2 = stream->codec; AVCodec *inAcodec = avcodec_find_decoder(stream->codec->codec_id); avcodec_open(stream->codec, inAcodec); AVCodec *outAcodec = avcodec_find_encoder(CODEC_ID_MP2); //ast2->codec = avcodec_alloc_context3(outAcodec); ast2->codec->bit_rate = 128000; ast2->codec->sample_rate = stream->codec->sample_rate; if(stream->codec->channels > 2) { stream->codec->request_channels = 2; } ast2->codec->channels = 2; ast2->codec->sample_fmt = AV_SAMPLE_FMT_S16; avcodec_open(ast2->codec, outAcodec); ast2->codec->time_base = infmt_ctx->streams[audio2]->time_base; ring_buffer_init(&adecrbuffer2, 524288); } else { avcodec_copy_context(ast2->codec, infmt_ctx->streams[audio2]->codec); //ast2->codec->time_base = infmt_ctx->streams[audio2]->time_base; ast2->stream_copy = 1; ast2->first_dts = infmt_ctx->streams[audio2]->first_dts; ast2->r_frame_rate = infmt_ctx->streams[audio2]->r_frame_rate; ast2->time_base = infmt_ctx->streams[audio2]->time_base; ast2->quality = infmt_ctx->streams[audio2]->quality; ast2->start_time = infmt_ctx->streams[audio2]->start_time; ast2->duration = infmt_ctx->streams[audio2]->duration; } } } init_put_byte(&outputpb, outputbuffer, MAIN_BUFFER_SIZE, 1, &outputringbuffer, NULL, write_data, NULL ); oc->pb = &outputpb; avformat_write_header(oc, NULL); //av_dump_format(oc, 0, "output.ts", 1); if(infmt_ctx->streams[video]->codec->codec_id == CODEC_ID_H264) { FFMPEG_DEBUG("open h264_mp4toannexb filter"); bsfc = av_bitstream_filter_init("h264_mp4toannexb"); if (!bsfc) { FFMPEG_ERROR("Cannot open the h264_mp4toannexb BSF!"); return -1; } } } return 0; }
static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp) { bool success = 0; AVFrame *pic = NULL; AVPacket pkt = {0}; int got_output = 0; av_init_packet(&pkt); struct AVCodec *codec = avcodec_find_encoder(ctx->writer->lavc_codec); AVCodecContext *avctx = NULL; if (!codec) goto print_open_fail; avctx = avcodec_alloc_context3(codec); if (!avctx) goto print_open_fail; avctx->time_base = AV_TIME_BASE_Q; avctx->width = image->w; avctx->height = image->h; avctx->pix_fmt = imgfmt2pixfmt(image->imgfmt); if (avctx->pix_fmt == AV_PIX_FMT_NONE) { MP_ERR(ctx, "Image format %s not supported by lavc.\n", mp_imgfmt_to_name(image->imgfmt)); goto error_exit; } if (ctx->writer->lavc_codec == AV_CODEC_ID_PNG) { avctx->compression_level = ctx->opts->png_compression; av_opt_set_int(avctx, "pred", ctx->opts->png_filter, AV_OPT_SEARCH_CHILDREN); } if (avcodec_open2(avctx, codec, NULL) < 0) { print_open_fail: MP_ERR(ctx, "Could not open libavcodec encoder for saving images\n"); goto error_exit; } pic = av_frame_alloc(); if (!pic) goto error_exit; for (int n = 0; n < 4; n++) { pic->data[n] = image->planes[n]; pic->linesize[n] = image->stride[n]; } pic->format = avctx->pix_fmt; pic->width = avctx->width; pic->height = avctx->height; if (ctx->opts->tag_csp) { pic->color_primaries = mp_csp_prim_to_avcol_pri(image->params.primaries); pic->color_trc = mp_csp_trc_to_avcol_trc(image->params.gamma); } int ret = avcodec_encode_video2(avctx, &pkt, pic, &got_output); if (ret < 0) goto error_exit; fwrite(pkt.data, pkt.size, 1, fp); success = !!got_output; error_exit: if (avctx) avcodec_close(avctx); av_free(avctx); av_frame_free(&pic); av_packet_unref(&pkt); return success; }
FFmpegVideo::FFmpegVideo() { avcodec_register_all(); // Encoding encoding_codec = NULL ; encoding_frame_buffer = NULL ; encoding_context = NULL ; //AVCodecID codec_id = AV_CODEC_ID_H264 ; //AVCodecID codec_id = AV_CODEC_ID_MPEG2VIDEO; #if LIBAVCODEC_VERSION_MAJOR < 54 CodecID codec_id = CODEC_ID_MPEG4; #else AVCodecID codec_id = AV_CODEC_ID_MPEG4; #endif /* find the video encoder */ encoding_codec = avcodec_find_encoder(codec_id); if (!encoding_codec) std::cerr << "AV codec not found for codec id " << std::endl; if (!encoding_codec) throw std::runtime_error("AV codec not found for codec id ") ; encoding_context = avcodec_alloc_context3(encoding_codec); if (!encoding_context) std::cerr << "AV: Could not allocate video codec encoding context" << std::endl; if (!encoding_context) throw std::runtime_error("AV: Could not allocate video codec encoding context"); /* put sample parameters */ encoding_context->bit_rate = 10*1024 ; // default bitrate is 30KB/s encoding_context->bit_rate_tolerance = encoding_context->bit_rate ; #ifdef USE_VARIABLE_BITRATE encoding_context->rc_min_rate = 0; encoding_context->rc_max_rate = 10*1024;//encoding_context->bit_rate; encoding_context->rc_buffer_size = 10*1024*1024; encoding_context->rc_initial_buffer_occupancy = (int) ( 0.9 * encoding_context->rc_buffer_size); encoding_context->rc_max_available_vbv_use = 1.0; encoding_context->rc_min_vbv_overflow_use = 0.0; #else encoding_context->rc_min_rate = 0; encoding_context->rc_max_rate = 0; encoding_context->rc_buffer_size = 0; #endif if (encoding_codec->capabilities & CODEC_CAP_TRUNCATED) encoding_context->flags |= CODEC_FLAG_TRUNCATED; encoding_context->flags |= CODEC_FLAG_PSNR;//Peak signal-to-noise ratio encoding_context->flags |= CODEC_CAP_PARAM_CHANGE; encoding_context->i_quant_factor = 0.769f; encoding_context->b_quant_factor = 1.4f; encoding_context->time_base.num = 1; encoding_context->time_base.den = 15;//framesPerSecond; encoding_context->qmin = 1; encoding_context->qmax = 51; encoding_context->max_qdiff = 4; //encoding_context->me_method = ME_HEX; //encoding_context->max_b_frames = 4; //encoding_context->flags |= CODEC_FLAG_LOW_DELAY; // MPEG2 only //encoding_context->partitions = X264_PART_I4X4 | X264_PART_I8X8 | X264_PART_P8X8 | X264_PART_P4X4 | X264_PART_B8X8; //encoding_context->crf = 0.0f; //encoding_context->cqp = 26; /* resolution must be a multiple of two */ encoding_context->width = 640;//176; encoding_context->height = 480;//144; /* frames per second */ encoding_context->time_base = av_make_q(1, 25); /* emit one intra frame every ten frames * check frame pict_type before passing frame * to encoder, if frame->pict_type is AV_PICTURE_TYPE_I * then gop_size is ignored and the output of encoder * will always be I frame irrespective to gop_size */ encoding_context->gop_size = 100; //encoding_context->max_b_frames = 1; #if LIBAVCODEC_VERSION_MAJOR < 54 encoding_context->pix_fmt = PIX_FMT_YUV420P; //context->pix_fmt = PIX_FMT_RGB24; if (codec_id == CODEC_ID_H264) { #else encoding_context->pix_fmt = AV_PIX_FMT_YUV420P; //context->pix_fmt = AV_PIX_FMT_RGB24; if (codec_id == AV_CODEC_ID_H264) { #endif av_opt_set(encoding_context->priv_data, "preset", "slow", 0); } /* open it */ if (avcodec_open2(encoding_context, encoding_codec, NULL) < 0) { std::cerr << "AV: Could not open codec context. Something's wrong." << std::endl; throw std::runtime_error( "AV: Could not open codec context. Something's wrong."); } #if (LIBAVCODEC_VERSION_MAJOR < 57) | (LIBAVCODEC_VERSION_MAJOR == 57 && LIBAVCODEC_VERSION_MINOR <3 ) encoding_frame_buffer = avcodec_alloc_frame() ;//(AVFrame*)malloc(sizeof(AVFrame)) ; #else encoding_frame_buffer = av_frame_alloc() ; #endif if(!encoding_frame_buffer) std::cerr << "AV: could not allocate frame buffer." << std::endl; if(!encoding_frame_buffer) throw std::runtime_error("AV: could not allocate frame buffer.") ; encoding_frame_buffer->format = encoding_context->pix_fmt; encoding_frame_buffer->width = encoding_context->width; encoding_frame_buffer->height = encoding_context->height; /* the image can be allocated by any means and av_image_alloc() is * just the most convenient way if av_malloc() is to be used */ int ret = av_image_alloc(encoding_frame_buffer->data, encoding_frame_buffer->linesize, encoding_context->width, encoding_context->height, encoding_context->pix_fmt, 32); if (ret < 0) std::cerr << "AV: Could not allocate raw picture buffer" << std::endl; if (ret < 0) throw std::runtime_error("AV: Could not allocate raw picture buffer"); encoding_frame_count = 0 ; // Decoding decoding_codec = avcodec_find_decoder(codec_id); if (!decoding_codec) std::cerr << "AV codec not found for codec id " << std::endl; if (!decoding_codec) throw("AV codec not found for codec id ") ; decoding_context = avcodec_alloc_context3(decoding_codec); if(!decoding_context) std::cerr << "AV: Could not allocate video codec decoding context" << std::endl; if(!decoding_context) throw std::runtime_error("AV: Could not allocate video codec decoding context"); decoding_context->width = encoding_context->width; decoding_context->height = encoding_context->height; #if LIBAVCODEC_VERSION_MAJOR < 54 decoding_context->pix_fmt = PIX_FMT_YUV420P; #else decoding_context->pix_fmt = AV_PIX_FMT_YUV420P; #endif if(decoding_codec->capabilities & CODEC_CAP_TRUNCATED) decoding_context->flags |= CODEC_FLAG_TRUNCATED; // we do not send complete frames //we can receive truncated frames decoding_context->flags2 |= CODEC_FLAG2_CHUNKS; AVDictionary* dictionary = NULL; if(avcodec_open2(decoding_context, decoding_codec, &dictionary) < 0) { std::cerr << "AV codec open action failed! " << std::endl; throw("AV codec open action failed! ") ; } //decoding_frame_buffer = avcodec_alloc_frame() ;//(AVFrame*)malloc(sizeof(AVFrame)) ; decoding_frame_buffer = av_frame_alloc() ; av_init_packet(&decoding_buffer); decoding_buffer.data = NULL ; decoding_buffer.size = 0 ; //ret = av_image_alloc(decoding_frame_buffer->data, decoding_frame_buffer->linesize, decoding_context->width, decoding_context->height, decoding_context->pix_fmt, 32); //if (ret < 0) //throw std::runtime_error("AV: Could not allocate raw picture buffer"); // debug #ifdef DEBUG_MPEG_VIDEO std::cerr << "Dumping captured data to file tmpvideo.mpg" << std::endl; encoding_debug_file = fopen("tmpvideo.mpg","w") ; #endif } FFmpegVideo::~FFmpegVideo() { avcodec_free_context(&encoding_context); avcodec_free_context(&decoding_context); av_frame_free(&encoding_frame_buffer); av_frame_free(&decoding_frame_buffer); } #define MAX_FFMPEG_ENCODING_BITRATE 81920 bool FFmpegVideo::encodeData(const QImage& image, uint32_t target_encoding_bitrate, RsVOIPDataChunk& voip_chunk) { #ifdef DEBUG_MPEG_VIDEO std::cerr << "Encoding frame of size " << image.width() << "x" << image.height() << ", resized to " << encoding_frame_buffer->width << "x" << encoding_frame_buffer->height << " : "; #endif QImage input ; if(target_encoding_bitrate > MAX_FFMPEG_ENCODING_BITRATE) { std::cerr << "Max encodign bitrate eexceeded. Capping to " << MAX_FFMPEG_ENCODING_BITRATE << std::endl; target_encoding_bitrate = MAX_FFMPEG_ENCODING_BITRATE ; } //encoding_context->bit_rate = target_encoding_bitrate; encoding_context->rc_max_rate = target_encoding_bitrate; //encoding_context->bit_rate_tolerance = target_encoding_bitrate; if(image.width() != encoding_frame_buffer->width || image.height() != encoding_frame_buffer->height) input = image.scaled(QSize(encoding_frame_buffer->width,encoding_frame_buffer->height),Qt::IgnoreAspectRatio,Qt::SmoothTransformation) ; else input = image ; /* prepare a dummy image */ /* Y */ for (int y = 0; y < encoding_context->height/2; y++) for (int x = 0; x < encoding_context->width/2; x++) { QRgb pix00 = input.pixel(QPoint(2*x+0,2*y+0)) ; QRgb pix01 = input.pixel(QPoint(2*x+0,2*y+1)) ; QRgb pix10 = input.pixel(QPoint(2*x+1,2*y+0)) ; QRgb pix11 = input.pixel(QPoint(2*x+1,2*y+1)) ; int R00 = (pix00 >> 16) & 0xff ; int G00 = (pix00 >> 8) & 0xff ; int B00 = (pix00 >> 0) & 0xff ; int R01 = (pix01 >> 16) & 0xff ; int G01 = (pix01 >> 8) & 0xff ; int B01 = (pix01 >> 0) & 0xff ; int R10 = (pix10 >> 16) & 0xff ; int G10 = (pix10 >> 8) & 0xff ; int B10 = (pix10 >> 0) & 0xff ; int R11 = (pix11 >> 16) & 0xff ; int G11 = (pix11 >> 8) & 0xff ; int B11 = (pix11 >> 0) & 0xff ; int Y00 = (0.257 * R00) + (0.504 * G00) + (0.098 * B00) + 16 ; int Y01 = (0.257 * R01) + (0.504 * G01) + (0.098 * B01) + 16 ; int Y10 = (0.257 * R10) + (0.504 * G10) + (0.098 * B10) + 16 ; int Y11 = (0.257 * R11) + (0.504 * G11) + (0.098 * B11) + 16 ; float R = 0.25*(R00+R01+R10+R11) ; float G = 0.25*(G00+G01+G10+G11) ; float B = 0.25*(B00+B01+B10+B11) ; int U = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128 ; int V = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128 ; encoding_frame_buffer->data[0][(2*y+0) * encoding_frame_buffer->linesize[0] + 2*x+0] = std::min(255,std::max(0,Y00)); // Y encoding_frame_buffer->data[0][(2*y+0) * encoding_frame_buffer->linesize[0] + 2*x+1] = std::min(255,std::max(0,Y01)); // Y encoding_frame_buffer->data[0][(2*y+1) * encoding_frame_buffer->linesize[0] + 2*x+0] = std::min(255,std::max(0,Y10)); // Y encoding_frame_buffer->data[0][(2*y+1) * encoding_frame_buffer->linesize[0] + 2*x+1] = std::min(255,std::max(0,Y11)); // Y encoding_frame_buffer->data[1][y * encoding_frame_buffer->linesize[1] + x] = std::min(255,std::max(0,U));// Cr encoding_frame_buffer->data[2][y * encoding_frame_buffer->linesize[2] + x] = std::min(255,std::max(0,V));// Cb } encoding_frame_buffer->pts = encoding_frame_count++; /* encode the image */ int got_output = 0; AVPacket pkt ; av_init_packet(&pkt); #if LIBAVCODEC_VERSION_MAJOR < 54 pkt.size = avpicture_get_size(encoding_context->pix_fmt, encoding_context->width, encoding_context->height); pkt.data = (uint8_t*)av_malloc(pkt.size); // do // { int ret = avcodec_encode_video(encoding_context, pkt.data, pkt.size, encoding_frame_buffer) ; if (ret > 0) { got_output = ret; } #else pkt.data = NULL; // packet data will be allocated by the encoder pkt.size = 0; // do // { int ret = avcodec_encode_video2(encoding_context, &pkt, encoding_frame_buffer, &got_output) ; #endif if (ret < 0) { std::cerr << "Error encoding frame!" << std::endl; return false ; } // frame = NULL ; // next attempts: do not encode anything. Do this to just flush the buffer // // } while(got_output) ; if(got_output) { voip_chunk.data = rs_malloc(pkt.size + HEADER_SIZE) ; if(!voip_chunk.data) return false ; uint32_t flags = 0; ((unsigned char *)voip_chunk.data)[0] = VideoProcessor::VIDEO_PROCESSOR_CODEC_ID_MPEG_VIDEO & 0xff ; ((unsigned char *)voip_chunk.data)[1] = (VideoProcessor::VIDEO_PROCESSOR_CODEC_ID_MPEG_VIDEO >> 8) & 0xff ; ((unsigned char *)voip_chunk.data)[2] = flags & 0xff ; ((unsigned char *)voip_chunk.data)[3] = (flags >> 8) & 0xff ; memcpy(&((unsigned char*)voip_chunk.data)[HEADER_SIZE],pkt.data,pkt.size) ; voip_chunk.size = pkt.size + HEADER_SIZE; voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; #ifdef DEBUG_MPEG_VIDEO std::cerr << "Output : " << pkt.size << " bytes." << std::endl; fwrite(pkt.data,1,pkt.size,encoding_debug_file) ; fflush(encoding_debug_file) ; #endif av_free_packet(&pkt); return true ; } else {
//============================================================================== int IVSS_Interface_XSpace_Simulation(IVSS_SYSTEM* system, IVSS_SIMULATOR* simulator, IVSS_UNIT* unit) { if (unit->type == IVSS_TYPE_XSPACE_VIDEO) { #ifdef FFMPEG_SUPPORT IVSS_VARIABLE* variable; unsigned char out_buf[128000]; int size, out_size, i; IVSS_Unit_GetNode(system,unit,"VideoSignal",&variable); /*int i, out_size, size, x, y, outbuf_size; FILE *f; uint8_t *outbuf, *picture_buf; //double error_probability = 0.0; printf("Video encoding\n");*/ //First-time initialization (FIXME) if ((!av_codec) && (!av_context)) { av_codec = avcodec_find_encoder(CODEC_ID_MPEG1VIDEO); av_context = avcodec_alloc_context(); av_picture = avcodec_alloc_frame(); av_context->bit_rate = 100000; av_context->width = 352; av_context->height = 288; av_context->time_base.den = 25; //25 FPS av_context->time_base.num = 1; av_context->gop_size = 10; //I-frame period av_context->max_b_frames = 1; av_context->pix_fmt = PIX_FMT_YUV420P; if (avcodec_open(av_context, av_codec) < 0) { av_codec = 0; } size = av_context->width * av_context->height; av_picture->data[0] = av_picture_yuv; av_picture->data[1] = av_picture->data[0] + size; av_picture->data[2] = av_picture->data[1] + size / 4; av_picture->linesize[0] = av_context->width; av_picture->linesize[1] = av_context->width / 2; av_picture->linesize[2] = av_context->width / 2; } if (av_codec && (!system->is_paused)) { int x,y; //Convert frame to YUV //Y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16 //Cr = V = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128 //Cb = U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128 //Y for(y = 0; y < av_context->height; y++) { for(x = 0; x < av_context->width; x++) { av_picture->data[0][y * av_picture->linesize[0] + x] = 16 +0.257*av_picture_data[(y*352+x)*3+0] +0.504*av_picture_data[(y*352+x)*3+1] +0.098*av_picture_data[(y*352+x)*3+2];//+x+y*2; } } //Cb and Cr for(y = 0; y < av_context->height/2; y++) { for(x = 0; x < av_context->width/2; x++) { av_picture->data[1][y * av_picture->linesize[1] + x] = 128 +0.439*av_picture_data[(2*y*352+2*x)*3+0]+ -0.368*av_picture_data[(2*y*352+2*x)*3+1]+ -0.071*av_picture_data[(2*y*352+2*x)*3+2]; av_picture->data[2][y * av_picture->linesize[2] + x] = 128 -0.148*av_picture_data[(2*y*352+2*x)*3+0] -0.291*av_picture_data[(2*y*352+2*x)*3+1] +0.439*av_picture_data[(2*y*352+2*x)*3+2]; } } //Encode current frame out_size = avcodec_encode_video(av_context, out_buf, 128000, av_picture); for (i = 0; i < out_size; i++) IVSS_Variable_WriteBuffer(system,variable,out_buf[i]); //Encode delayed frames while (out_size) { out_size = avcodec_encode_video(av_context, out_buf, 128000, 0); for (i = 0; i < out_size; i++) IVSS_Variable_WriteBuffer(system,variable,out_buf[i]); } } /*avcodec_close(c); av_free(c); av_free(picture);*/ thread_sleep(1.0/60.0); #endif } else { thread_sleep(1000.0); } return IVSS_OK; }
bool CFFmpegImage::CreateThumbnailFromSurface(unsigned char* bufferin, unsigned int width, unsigned int height, unsigned int format, unsigned int pitch, const std::string& destFile, unsigned char* &bufferout, unsigned int &bufferoutSize) { // It seems XB_FMT_A8R8G8B8 mean RGBA and not ARGB if (format != XB_FMT_A8R8G8B8) { CLog::Log(LOGERROR, "Supplied format: %d is not supported.", format); return false; } bool jpg_output = false; if (m_strMimeType == "image/jpeg" || m_strMimeType == "image/jpg") jpg_output = true; else if (m_strMimeType == "image/png") jpg_output = false; else { CLog::Log(LOGERROR, "Output Format is not supported: %s is not supported.", destFile.c_str()); return false; } ThumbDataManagement tdm; tdm.codec = avcodec_find_encoder(jpg_output ? AV_CODEC_ID_MJPEG : AV_CODEC_ID_PNG); if (!tdm.codec) { CLog::Log(LOGERROR, "Your are missing a working encoder for format: %d", jpg_output ? AV_CODEC_ID_MJPEG : AV_CODEC_ID_PNG); return false; } tdm.avOutctx = avcodec_alloc_context3(tdm.codec); if (!tdm.avOutctx) { CLog::Log(LOGERROR, "Could not allocate context for thumbnail: %s", destFile.c_str()); return false; } tdm.avOutctx->height = height; tdm.avOutctx->width = width; tdm.avOutctx->time_base.num = 1; tdm.avOutctx->time_base.den = 1; tdm.avOutctx->pix_fmt = jpg_output ? AV_PIX_FMT_YUVJ420P : AV_PIX_FMT_RGBA; tdm.avOutctx->flags = CODEC_FLAG_QSCALE; tdm.avOutctx->mb_lmin = tdm.avOutctx->qmin * FF_QP2LAMBDA; tdm.avOutctx->mb_lmax = tdm.avOutctx->qmax * FF_QP2LAMBDA; tdm.avOutctx->global_quality = tdm.avOutctx->qmin * FF_QP2LAMBDA; unsigned int internalBufOutSize = 0; int size = avpicture_get_size(tdm.avOutctx->pix_fmt, tdm.avOutctx->width, tdm.avOutctx->height); if (size < 0) { CLog::Log(LOGERROR, "Could not compute picture size for thumbnail: %s", destFile.c_str()); CleanupLocalOutputBuffer(); return false; } internalBufOutSize = (unsigned int) size; m_outputBuffer = (uint8_t*) av_malloc(internalBufOutSize); if (!m_outputBuffer) { CLog::Log(LOGERROR, "Could not generate allocate memory for thumbnail: %s", destFile.c_str()); CleanupLocalOutputBuffer(); return false; } tdm.intermediateBuffer = (uint8_t*) av_malloc(internalBufOutSize); if (!tdm.intermediateBuffer) { CLog::Log(LOGERROR, "Could not allocate memory for thumbnail: %s", destFile.c_str()); CleanupLocalOutputBuffer(); return false; } if (avcodec_open2(tdm.avOutctx, tdm.codec, NULL) < 0) { CLog::Log(LOGERROR, "Could not open avcodec context thumbnail: %s", destFile.c_str()); CleanupLocalOutputBuffer(); return false; } tdm.frame_input = av_frame_alloc(); if (!tdm.frame_input) { CLog::Log(LOGERROR, "Could not allocate frame for thumbnail: %s", destFile.c_str()); CleanupLocalOutputBuffer(); return false; } // convert the RGB32 frame to AV_PIX_FMT_YUV420P - we use this later on as AV_PIX_FMT_YUVJ420P tdm.frame_temporary = av_frame_alloc(); if (!tdm.frame_temporary) { CLog::Log(LOGERROR, "Could not allocate frame for thumbnail: %s", destFile.c_str()); CleanupLocalOutputBuffer(); return false; } if (avpicture_fill((AVPicture*)tdm.frame_temporary, tdm.intermediateBuffer, jpg_output ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_RGBA, width, height) < 0) { CLog::Log(LOGERROR, "Could not fill picture for thumbnail: %s", destFile.c_str()); CleanupLocalOutputBuffer(); return false; } uint8_t* src[] = { bufferin, NULL, NULL, NULL }; int srcStride[] = { (int) pitch, 0, 0, 0}; //input size == output size which means only pix_fmt conversion tdm.sws = sws_getContext(width, height, AV_PIX_FMT_RGB32, width, height, jpg_output ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_RGBA, 0, 0, 0, 0); if (!tdm.sws) { CLog::Log(LOGERROR, "Could not setup scaling context for thumbnail: %s", destFile.c_str()); CleanupLocalOutputBuffer(); return false; } // Setup jpeg range for sws if (jpg_output) { int* inv_table = nullptr; int* table = nullptr; int srcRange, dstRange, brightness, contrast, saturation; if (sws_getColorspaceDetails(tdm.sws, &inv_table, &srcRange, &table, &dstRange, &brightness, &contrast, &saturation) < 0) { CLog::Log(LOGERROR, "SWS_SCALE failed to get ColorSpaceDetails for thumbnail: %s", destFile.c_str()); CleanupLocalOutputBuffer(); return false; } dstRange = 1; // jpeg full range yuv420p output srcRange = 0; // full range RGB32 input if (sws_setColorspaceDetails(tdm.sws, inv_table, srcRange, table, dstRange, brightness, contrast, saturation) < 0) { CLog::Log(LOGERROR, "SWS_SCALE failed to set ColorSpace Details for thumbnail: %s", destFile.c_str()); CleanupLocalOutputBuffer(); return false; } } if (sws_scale(tdm.sws, src, srcStride, 0, height, tdm.frame_temporary->data, tdm.frame_temporary->linesize) < 0) { CLog::Log(LOGERROR, "SWS_SCALE failed for thumbnail: %s", destFile.c_str()); CleanupLocalOutputBuffer(); return false; } tdm.frame_input->pts = 1; tdm.frame_input->quality = tdm.avOutctx->global_quality; tdm.frame_input->data[0] = (uint8_t*) tdm.frame_temporary->data[0]; tdm.frame_input->data[1] = (uint8_t*) tdm.frame_temporary->data[1]; tdm.frame_input->data[2] = (uint8_t*) tdm.frame_temporary->data[2]; tdm.frame_input->height = height; tdm.frame_input->width = width; tdm.frame_input->linesize[0] = tdm.frame_temporary->linesize[0]; tdm.frame_input->linesize[1] = tdm.frame_temporary->linesize[1]; tdm.frame_input->linesize[2] = tdm.frame_temporary->linesize[2]; // this is deprecated but mjpeg is not yet transitioned tdm.frame_input->format = jpg_output ? AV_PIX_FMT_YUVJ420P : AV_PIX_FMT_RGBA; int got_package = 0; AVPacket avpkt; av_init_packet(&avpkt); avpkt.data = m_outputBuffer; avpkt.size = internalBufOutSize; if ((avcodec_encode_video2(tdm.avOutctx, &avpkt, tdm.frame_input, &got_package) < 0) || (got_package == 0)) { CLog::Log(LOGERROR, "Could not encode thumbnail: %s", destFile.c_str()); CleanupLocalOutputBuffer(); return false; } bufferoutSize = avpkt.size; bufferout = m_outputBuffer; return true; }
struct iaxc_video_codec *codec_video_ffmpeg_new(int format, int w, int h, int framerate, int bitrate, int fragsize) { struct encoder_ctx *e; struct decoder_ctx *d; AVCodec *codec; int ff_enc_id, ff_dec_id; char *name; struct iaxc_video_codec *c = calloc(sizeof(struct iaxc_video_codec), 1); if (!c) { fprintf(stderr, "codec_ffmpeg: failed to allocate video context\n"); return NULL; } avcodec_init(); avcodec_register_all(); c->format = format; c->width = w; c->height = h; c->framerate = framerate; c->bitrate = bitrate; /* TODO: Is a fragsize of zero valid? If so, there's a divide * by zero error to contend with. */ c->fragsize = fragsize; c->encode = encode; c->decode = decode_iaxc_slice; c->destroy = destroy; c->encstate = calloc(sizeof(struct encoder_ctx), 1); if (!c->encstate) goto bail; e = c->encstate; e->avctx = avcodec_alloc_context(); if (!e->avctx) goto bail; e->picture = avcodec_alloc_frame(); if (!e->picture) goto bail; /* The idea here is that the encoded frame that will land in this * buffer will be no larger than the size of an uncompressed 32-bit * rgb frame. * * TODO: Is this assumption really valid? */ e->frame_buf_len = w * h * 4; e->frame_buf = malloc(e->frame_buf_len); if (!e->frame_buf) goto bail; c->decstate = calloc(sizeof(struct decoder_ctx), 1); if (!c->decstate) goto bail; d = c->decstate; d->avctx = avcodec_alloc_context(); if (!d->avctx) goto bail; d->picture = avcodec_alloc_frame(); if (!d->picture) goto bail; d->frame_buf_len = e->frame_buf_len; d->frame_buf = malloc(d->frame_buf_len); if (!d->frame_buf) goto bail; e->slice_header.version = 0; srandom(time(0)); e->slice_header.source_id = random() & 0xffff; e->avctx->time_base.num = 1; e->avctx->time_base.den = framerate; e->avctx->width = w; e->avctx->height = h; e->avctx->bit_rate = bitrate; /* This determines how often i-frames are sent */ e->avctx->gop_size = framerate * 3; e->avctx->pix_fmt = PIX_FMT_YUV420P; e->avctx->has_b_frames = 0; e->avctx->mb_qmin = e->avctx->qmin = 10; e->avctx->mb_qmax = e->avctx->qmax = 10; e->avctx->lmin = 2 * FF_QP2LAMBDA; e->avctx->lmax = 10 * FF_QP2LAMBDA; e->avctx->global_quality = FF_QP2LAMBDA * 2; e->avctx->qblur = 0.5; e->avctx->global_quality = 10; e->avctx->flags |= CODEC_FLAG_PSNR; e->avctx->flags |= CODEC_FLAG_QSCALE; e->avctx->mb_decision = FF_MB_DECISION_SIMPLE; ff_enc_id = ff_dec_id = map_iaxc_codec_to_avcodec(format); /* Note, when fragsize is used (non-zero) ffmpeg will use a "best * effort" strategy: the fragment size will be fragsize +/- 20% */ switch (format) { case IAXC_FORMAT_H261: /* TODO: H261 only works with specific resolutions. */ name = "H.261"; break; case IAXC_FORMAT_H263: /* TODO: H263 only works with specific resolutions. */ name = "H.263"; e->avctx->flags |= CODEC_FLAG_AC_PRED; if (fragsize) { c->decode = decode_rtp_slice; e->avctx->rtp_payload_size = fragsize; e->avctx->flags |= CODEC_FLAG_TRUNCATED | CODEC_FLAG2_STRICT_GOP; e->avctx->rtp_callback = encode_rtp_callback; d->avctx->flags |= CODEC_FLAG_TRUNCATED; } break; case IAXC_FORMAT_H263_PLUS: /* Although the encoder is CODEC_ID_H263P, the decoder * is the regular h.263, so we handle this special case * here. */ ff_dec_id = CODEC_ID_H263; name = "H.263+"; e->avctx->flags |= CODEC_FLAG_AC_PRED; if (fragsize) { c->decode = decode_rtp_slice; e->avctx->rtp_payload_size = fragsize; e->avctx->flags |= CODEC_FLAG_TRUNCATED | CODEC_FLAG_H263P_SLICE_STRUCT | CODEC_FLAG2_STRICT_GOP | CODEC_FLAG2_LOCAL_HEADER; e->avctx->rtp_callback = encode_rtp_callback; d->avctx->flags |= CODEC_FLAG_TRUNCATED; } break; case IAXC_FORMAT_MPEG4: name = "MPEG4"; c->decode = decode_rtp_slice; e->avctx->rtp_payload_size = fragsize; e->avctx->rtp_callback = encode_rtp_callback; e->avctx->flags |= CODEC_FLAG_TRUNCATED | CODEC_FLAG_H263P_SLICE_STRUCT | CODEC_FLAG2_STRICT_GOP | CODEC_FLAG2_LOCAL_HEADER; d->avctx->flags |= CODEC_FLAG_TRUNCATED; break; case IAXC_FORMAT_H264: name = "H.264"; /* * Encoder flags */ /* Headers are not repeated */ /* e->avctx->flags |= CODEC_FLAG_GLOBAL_HEADER; */ /* Slower, less blocky */ /* e->avctx->flags |= CODEC_FLAG_LOOP_FILTER; */ e->avctx->flags |= CODEC_FLAG_PASS1; /* e->avctx->flags |= CODEC_FLAG_PASS2; */ /* Compute psnr values at encode-time (avctx->error[]) */ /* e->avctx->flags |= CODEC_FLAG_PSNR; */ /* e->avctx->flags2 |= CODEC_FLAG2_8X8DCT; */ /* Access Unit Delimiters */ e->avctx->flags2 |= CODEC_FLAG2_AUD; /* Allow b-frames to be used as reference */ /* e->avctx->flags2 |= CODEC_FLAG2_BPYRAMID; */ /* b-frame rate distortion optimization */ /* e->avctx->flags2 |= CODEC_FLAG2_BRDO; */ /* e->avctx->flags2 |= CODEC_FLAG2_FASTPSKIP; */ /* Multiple references per partition */ /* e->avctx->flags2 |= CODEC_FLAG2_MIXED_REFS; */ /* Weighted biprediction for b-frames */ /* e->avctx->flags2 |= CODEC_FLAG2_WPRED; */ /* * Decoder flags */ /* Do not draw edges */ /* d->avctx->flags |= CODEC_FLAG_EMU_EDGE; */ /* Decode grayscale only */ /* d->avctx->flags |= CODEC_FLAG_GRAY; */ /* d->avctx->flags |= CODEC_FLAG_LOW_DELAY; */ /* Allow input bitstream to be randomly truncated */ /* d->avctx->flags |= CODEC_FLAG_TRUNCATED; */ /* Allow out-of-spec speed tricks */ /* d->avctx->flags2 |= CODEC_FLAG2_FAST; */ break; case IAXC_FORMAT_THEORA: /* TODO: ffmpeg only has a theora decoder. Until it has * an encoder also, we cannot use ffmpeg for theora. */ name = "Theora"; break; default: fprintf(stderr, "codec_ffmpeg: unsupported format (0x%08x)\n", format); goto bail; } strcpy(c->name, "ffmpeg-"); strncat(c->name, name, sizeof(c->name)); /* Get the codecs */ codec = avcodec_find_encoder(ff_enc_id); if (!codec) { iaxci_usermsg(IAXC_TEXT_TYPE_ERROR, "codec_ffmpeg: cannot find encoder %d\n", ff_enc_id); goto bail; } if (avcodec_open(e->avctx, codec)) { iaxci_usermsg(IAXC_TEXT_TYPE_ERROR, "codec_ffmpeg: cannot open encoder %s\n", name); goto bail; } codec = avcodec_find_decoder(ff_dec_id); if (!codec) { iaxci_usermsg(IAXC_TEXT_TYPE_ERROR, "codec_ffmpeg: cannot find decoder %d\n", ff_dec_id); goto bail; } if (avcodec_open(d->avctx, codec)) { iaxci_usermsg(IAXC_TEXT_TYPE_ERROR, "codec_ffmpeg: cannot open decoder %s\n", name); goto bail; } { enum PixelFormat fmts[] = { PIX_FMT_YUV420P, -1 }; if (d->avctx->get_format(d->avctx, fmts) != PIX_FMT_YUV420P) { iaxci_usermsg(IAXC_TEXT_TYPE_ERROR, "codec_ffmpeg: cannot set decode format to YUV420P\n"); goto bail; } } return c; bail: destroy(c); return 0; }
/** * ffmpeg_open * Opens an mpeg file using the new libavformat method. Both mpeg1 * and mpeg4 are supported. However, if the current ffmpeg version doesn't allow * mpeg1 with non-standard framerate, the open will fail. Timelapse is a special * case and is tested separately. * * Returns * A new allocated ffmpeg struct or NULL if any error happens. */ struct ffmpeg *ffmpeg_open(char *ffmpeg_video_codec, char *filename, unsigned char *y, unsigned char *u, unsigned char *v, int width, int height, int rate, int bps, int vbr) { AVCodecContext *c; AVCodec *codec; struct ffmpeg *ffmpeg; int is_mpeg1; int ret; /* * Allocate space for our ffmpeg structure. This structure contains all the * codec and image information we need to generate movies. * FIXME when motion exits we should close the movie to ensure that * ffmpeg is freed. */ ffmpeg = mymalloc(sizeof(struct ffmpeg)); memset(ffmpeg, 0, sizeof(struct ffmpeg)); ffmpeg->vbr = vbr; /* Store codec name in ffmpeg->codec, with buffer overflow check. */ snprintf(ffmpeg->codec, sizeof(ffmpeg->codec), "%s", ffmpeg_video_codec); /* Allocation the output media context. */ #ifdef have_avformat_alloc_context ffmpeg->oc = avformat_alloc_context(); #elif defined have_av_avformat_alloc_context ffmpeg->oc = av_alloc_format_context(); #else ffmpeg->oc = av_mallocz(sizeof(AVFormatContext)); #endif if (!ffmpeg->oc) { MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO, "%s: Memory error while allocating" " output media context"); ffmpeg_cleanups(ffmpeg); return NULL; } /* Setup output format */ ffmpeg->oc->oformat = get_oformat(ffmpeg_video_codec, filename); if (!ffmpeg->oc->oformat) { ffmpeg_cleanups(ffmpeg); return NULL; } snprintf(ffmpeg->oc->filename, sizeof(ffmpeg->oc->filename), "%s", filename); /* Create a new video stream and initialize the codecs. */ ffmpeg->video_st = NULL; if (ffmpeg->oc->oformat->video_codec != CODEC_ID_NONE) { #if defined FF_API_NEW_AVIO ffmpeg->video_st = avformat_new_stream(ffmpeg->oc, NULL /* Codec */); #else ffmpeg->video_st = av_new_stream(ffmpeg->oc, 0); #endif if (!ffmpeg->video_st) { MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO, "%s: av_new_stream - could" " not alloc stream"); ffmpeg_cleanups(ffmpeg); return NULL; } } else { /* We did not get a proper video codec. */ MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: Failed to obtain a proper" " video codec"); ffmpeg_cleanups(ffmpeg); return NULL; } ffmpeg->c = c = AVSTREAM_CODEC_PTR(ffmpeg->video_st); c->codec_id = ffmpeg->oc->oformat->video_codec; #if LIBAVCODEC_VERSION_MAJOR < 53 c->codec_type = CODEC_TYPE_VIDEO; #else c->codec_type = AVMEDIA_TYPE_VIDEO; #endif is_mpeg1 = c->codec_id == CODEC_ID_MPEG1VIDEO; if (strcmp(ffmpeg_video_codec, "ffv1") == 0) c->strict_std_compliance = -2; /* Uncomment to allow non-standard framerates. */ //c->strict_std_compliance = -1; /* Set default parameters */ c->bit_rate = bps; c->width = width; c->height = height; #if LIBAVCODEC_BUILD >= 4754 /* Frame rate = 1/time_base, so we set 1/rate, not rate/1 */ c->time_base.num = 1; c->time_base.den = rate; #else c->frame_rate = rate; c->frame_rate_base = 1; #endif /* LIBAVCODEC_BUILD >= 4754 */ MOTION_LOG(INF, TYPE_ENCODER, NO_ERRNO, "%s FPS %d", rate); if (vbr) c->flags |= CODEC_FLAG_QSCALE; /* * Set codec specific parameters. * Set intra frame distance in frames depending on codec. */ c->gop_size = is_mpeg1 ? 10 : 12; /* Some formats want stream headers to be separate. */ if (!strcmp(ffmpeg->oc->oformat->name, "mp4") || !strcmp(ffmpeg->oc->oformat->name, "mov") || !strcmp(ffmpeg->oc->oformat->name, "3gp")) { c->flags |= CODEC_FLAG_GLOBAL_HEADER; } #if defined FF_API_NEW_AVIO // pass the options to avformat_write_header directly #else /* Set the output parameters (must be done even if no parameters). */ if (av_set_parameters(ffmpeg->oc, NULL) < 0) { MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: av_set_parameters error:" " Invalid output format parameters"); ffmpeg_cleanups(ffmpeg); return NULL; } #endif /* Dump the format settings. This shows how the various streams relate to each other. */ //dump_format(ffmpeg->oc, 0, filename, 1); /* * Now that all the parameters are set, we can open the video * codec and allocate the necessary encode buffers. */ codec = avcodec_find_encoder(c->codec_id); if (!codec) { MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: Codec %s not found", ffmpeg_video_codec); ffmpeg_cleanups(ffmpeg); return NULL; } /* Set the picture format - need in ffmpeg starting round April-May 2005 */ c->pix_fmt = PIX_FMT_YUV420P; /* Get a mutex lock. */ pthread_mutex_lock(&global_lock); /* Open the codec */ #if defined FF_API_NEW_AVIO ret = avcodec_open2(c, codec, NULL /* options */ ); #else ret = avcodec_open(c, codec); #endif if (ret < 0) { /* Release the lock. */ pthread_mutex_unlock(&global_lock); MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: avcodec_open - could not open codec %s", ffmpeg_video_codec); ffmpeg_cleanups(ffmpeg); return NULL; } /* Release the lock. */ pthread_mutex_unlock(&global_lock); ffmpeg->video_outbuf = NULL; if (!(ffmpeg->oc->oformat->flags & AVFMT_RAWPICTURE)) { /* * Allocate output buffer * XXX: API change will be done * ffmpeg->video_outbuf_size = 200000 */ ffmpeg->video_outbuf_size = ffmpeg->c->width * 512; ffmpeg->video_outbuf = mymalloc(ffmpeg->video_outbuf_size); } /* Allocate the encoded raw picture. */ ffmpeg->picture = avcodec_alloc_frame(); if (!ffmpeg->picture) { MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: avcodec_alloc_frame -" " could not alloc frame"); ffmpeg_cleanups(ffmpeg); return NULL; } /* Set variable bitrate if requested. */ if (ffmpeg->vbr) ffmpeg->picture->quality = ffmpeg->vbr; /* Set the frame data. */ ffmpeg->picture->data[0] = y; ffmpeg->picture->data[1] = u; ffmpeg->picture->data[2] = v; ffmpeg->picture->linesize[0] = ffmpeg->c->width; ffmpeg->picture->linesize[1] = ffmpeg->c->width / 2; ffmpeg->picture->linesize[2] = ffmpeg->c->width / 2; /* Open the output file, if needed. */ if (!(ffmpeg->oc->oformat->flags & AVFMT_NOFILE)) { char file_proto[256]; /* * Use append file protocol for mpeg1, to get the append behavior from * url_fopen, but no protocol (=> default) for other codecs. */ if (is_mpeg1) #if defined FF_API_NEW_AVIO snprintf(file_proto, sizeof(file_proto), "%s", filename); #else snprintf(file_proto, sizeof(file_proto), APPEND_PROTO ":%s", filename); #endif else
MediaRet MediaRecorder::setup_video_stream(const char *fname, int w, int h, int d) { AVCodecContext *ctx; vid_st = av_new_stream(oc, 0); if(!vid_st) { avformat_free_context(oc); oc = NULL; return MRET_ERR_NOMEM; } ctx = vid_st->codec; ctx->codec_id = oc->oformat->video_codec; ctx->codec_type = AVMEDIA_TYPE_VIDEO; ctx->width = w; ctx->height = h; ctx->time_base.den = 60; ctx->time_base.num = 1; // dunno if any of these help; some output just looks plain crappy // will have to investigate further ctx->bit_rate = 400000; ctx->gop_size = 12; ctx->max_b_frames = 2; switch(d) { case 16: // FIXME: test & make endian-neutral pixfmt = PIX_FMT_RGB565LE; break; case 24: pixfmt = PIX_FMT_RGB24; break; case 32: default: // should never be anything else pixfmt = PIX_FMT_RGBA; break; } ctx->pix_fmt = pixfmt; pixsize = d >> 3; linesize = pixsize * w; ctx->max_b_frames = 2; if(oc->oformat->flags & AVFMT_GLOBALHEADER) ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; AVCodec *codec = avcodec_find_encoder(oc->oformat->video_codec); // make sure RGB is supported (mostly not) if(codec->pix_fmts) { const enum PixelFormat *p; int64_t mask = 0; for(p = codec->pix_fmts; *p != -1; p++) { // may get complaints about 1LL; thus the cast mask |= ((int64_t)1) << *p; if(*p == pixfmt) break; } if(*p == -1) { // if not supported, use a converter to the next best format // this is swscale, the converter used by the output demo enum PixelFormat dp = (PixelFormat)avcodec_find_best_pix_fmt(mask, pixfmt, 0, NULL); if(dp == -1) dp = codec->pix_fmts[0]; if(!(convpic = avcodec_alloc_frame()) || avpicture_alloc((AVPicture *)convpic, dp, w, h) < 0) { avformat_free_context(oc); oc = NULL; return MRET_ERR_NOMEM; } #if LIBSWSCALE_VERSION_INT < AV_VERSION_INT(0, 12, 0) converter = sws_getContext(w, h, pixfmt, w, h, dp, SWS_BICUBIC, NULL, NULL, NULL); #else converter = sws_alloc_context(); // what a convoluted, inefficient way to set options av_set_int(converter, "sws_flags", SWS_BICUBIC); av_set_int(converter, "srcw", w); av_set_int(converter, "srch", h); av_set_int(converter, "dstw", w); av_set_int(converter, "dsth", h); av_set_int(converter, "src_format", pixfmt); av_set_int(converter, "dst_format", dp); sws_init_context(converter, NULL, NULL); #endif ctx->pix_fmt = dp; } } if(!codec || avcodec_open(ctx, codec)) { avformat_free_context(oc); oc = NULL; return MRET_ERR_NOCODEC; } return MRET_OK; }
/** *发送一帧图像 *前四字节为所发送图像的尺寸,从低字节到高字节依次为width_high, width_low, height_high, height_low *后面为图像数据,每个像素3个字节,依次为RGB通道 */ void MapThread::sendFrame() { if(!started) return; if(!inited) { avcodec_register_all(); c= NULL; pkt = new AVPacket; i = 0; /* find the mpeg1 video encoder */ codec = avcodec_find_encoder(AV_CODEC_ID_MPEG1VIDEO); if (codec == 0) { exit(1); } c = avcodec_alloc_context3(codec); if (!c) { exit(1); } //c->bit_rate = 400000; c->width = dest_width; c->height = dest_height; AVRational ar = {1,25}; c->time_base = ar; c->gop_size = 100; c->max_b_frames = 0; c->delay = 0; c->pix_fmt = AV_PIX_FMT_YUV420P; //av_opt_set(c->priv_data, "preset", "slow", 0); av_opt_set(c->priv_data, "preset", "superfast", 0); av_opt_set(c->priv_data, "tune", "zerolatency", 0); int re = avcodec_open2(c, codec, NULL); av_opt_set(c->priv_data, "tune", "zerolatency", 0); if (re < 0) { exit(1); } frame = av_frame_alloc(); if (!frame) { exit(1); } frame->format = c->pix_fmt; frame->width = c->width; frame->height = c->height; ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height, c->pix_fmt, 32); if (ret < 0) { exit(1); } inited = true; } if(mapSocket == 0) { return; } else if(mapSocket->isOpen() == false) { return; } else if(mapSocket->isWritable() == false) { return; } QImage image = Interface::grapScreen().toImage(); image = image.scaled(QSize(dest_width, dest_height)); av_init_packet(pkt); pkt->data = NULL; // packet data will be allocated by the encoder pkt->size = 1000000; for (int h = 0; h < c->height; h++) { for (int w = 0; w < c->width; w++) { QRgb rgb = image.pixel(w, h); int r = qRed(rgb); int g = qGreen(rgb); int b = qBlue(rgb); int dy = ((66*r + 129*g + 25*b) >> 8) + 16; int du = ((-38*r + -74*g + 112*b) >> 8) + 128; int dv = ((112*r + -94*g + -18*b) >> 8) + 128; uchar yy = (uchar)dy; uchar uu = (uchar)du; uchar vv = (uchar)dv; frame->data[0][h * frame->linesize[0] + w] = yy; if(h % 2 == 0 && w % 2 == 0) { frame->data[1][h/2 * (frame->linesize[1]) + w/2] = uu; frame->data[2][h/2 * (frame->linesize[2]) + w/2] = vv; } } } frame->pts = i; ret = avcodec_encode_video2(c, pkt, frame, &got_output); if (ret < 0) { exit(1); } if (got_output) { int ss = pkt->size; writeAndBlock(mapSocket, pkt->data, ss); mapSocket->flush(); av_free_packet(pkt); } i ++; }
/* * Video encoding example */ static void video_encode_example(const char *filename, int codec_id) { AVCodec *codec; AVCodecContext *c= NULL; int i, ret, x, y, got_output; FILE *f; AVFrame *frame; AVPacket pkt; uint8_t endcode[] = { 0, 0, 1, 0xb7 }; printf("Encode video file %s\n", filename); /* find the mpeg1 video encoder */ codec = avcodec_find_encoder(codec_id); if (!codec) { fprintf(stderr, "Codec not found\n"); exit(1); } c = avcodec_alloc_context3(codec); if (!c) { fprintf(stderr, "Could not allocate video codec context\n"); exit(1); } /* put sample parameters */ c->bit_rate = 400000; /* resolution must be a multiple of two */ c->width = 352; c->height = 288; /* frames per second */ c->time_base= (AVRational){1,25}; c->gop_size = 10; /* emit one intra frame every ten frames */ c->max_b_frames=1; c->pix_fmt = PIX_FMT_YUV420P; if(codec_id == AV_CODEC_ID_H264) av_opt_set(c->priv_data, "preset", "slow", 0); /* open it */ if (avcodec_open2(c, codec, NULL) < 0) { fprintf(stderr, "Could not open codec\n"); exit(1); } f = fopen(filename, "wb"); if (!f) { fprintf(stderr, "Could not open %s\n", filename); exit(1); } frame = avcodec_alloc_frame(); if (!frame) { fprintf(stderr, "Could not allocate video frame\n"); exit(1); } frame->format = c->pix_fmt; frame->width = c->width; frame->height = c->height; /* the image can be allocated by any means and av_image_alloc() is * just the most convenient way if av_malloc() is to be used */ ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height, c->pix_fmt, 32); if (ret < 0) { fprintf(stderr, "Could not allocate raw picture buffer\n"); exit(1); } /* encode 1 second of video */ for(i=0;i<25;i++) { av_init_packet(&pkt); pkt.data = NULL; // packet data will be allocated by the encoder pkt.size = 0; fflush(stdout); /* prepare a dummy image */ /* Y */ for(y=0;y<c->height;y++) { for(x=0;x<c->width;x++) { frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3; } } /* Cb and Cr */ for(y=0;y<c->height/2;y++) { for(x=0;x<c->width/2;x++) { frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2; frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5; } } frame->pts = i; /* encode the image */ ret = avcodec_encode_video2(c, &pkt, frame, &got_output); if (ret < 0) { fprintf(stderr, "Error encoding frame\n"); exit(1); } if (got_output) { printf("Write frame %3d (size=%5d)\n", i, pkt.size); fwrite(pkt.data, 1, pkt.size, f); av_free_packet(&pkt); } } /* get the delayed frames */ for (got_output = 1; got_output; i++) { fflush(stdout); ret = avcodec_encode_video2(c, &pkt, NULL, &got_output); if (ret < 0) { fprintf(stderr, "Error encoding frame\n"); exit(1); } if (got_output) { printf("Write frame %3d (size=%5d)\n", i, pkt.size); fwrite(pkt.data, 1, pkt.size, f); av_free_packet(&pkt); } } /* add sequence end code to have a real mpeg file */ fwrite(endcode, 1, sizeof(endcode), f); fclose(f); avcodec_close(c); av_free(c); av_freep(&frame->data[0]); avcodec_free_frame(&frame); printf("\n"); }
void recorder::init_context(unsigned width, unsigned height) { assert(!avcontext_); if (output_.bad()) { goto init_failed; } outputfmt_ = av_guess_format ("avi", NULL, NULL); assert(outputfmt_); fmtcontext_ = avformat_alloc_context(); fmtcontext_->oformat = outputfmt_; std::copy(path_.begin(), path_.end(), fmtcontext_->filename); assert(outputfmt_->video_codec != CODEC_ID_NONE); video_st_ = avformat_new_stream(fmtcontext_, 0); assert(video_st_); avcontext_ = video_st_->codec; avcodec_ = avcodec_find_encoder(VIDEO_CODEC); avcodec_get_context_defaults3(avcontext_, avcodec_); yuvframe_ = avcodec_alloc_frame(); rgbframe_ = avcodec_alloc_frame(); avcontext_->codec_id = VIDEO_CODEC; avcontext_->codec_type = AVMEDIA_TYPE_VIDEO; avcontext_->width = width; avcontext_->height = height; avcontext_->flags = CODEC_FLAG_4MV | CODEC_FLAG_AC_PRED | CODEC_FLAG_PASS1; avcontext_->mb_decision = FF_MB_DECISION_RD; avcontext_->me_cmp = 2; avcontext_->me_sub_cmp = 2; avcontext_->trellis = 2; avcontext_->bit_rate = 2000000*1000; avcontext_->bit_rate_tolerance = avcontext_->bit_rate; avcontext_->b_frame_strategy = 1; avcontext_->coder_type = 1; avcontext_->me_method = ME_EPZS; avcontext_->me_subpel_quality = 5; avcontext_->i_quant_factor = 0.71; avcontext_->qcompress = 0.6; avcontext_->max_qdiff = 4; //DEPRECATED avcontext_->directpred = 1; avcontext_->gop_size = 300; avcontext_->max_b_frames=3; avcontext_->time_base.den = frame_per_seconds_; avcontext_->time_base.num = 1; avcontext_->pix_fmt = FRAME_FORMAT; av_dump_format(fmtcontext_, 0, path_.c_str(), 1); // find the mpeg1 video encoder if (!avcodec_) { std::cerr << "Codec not found" << std::endl; goto init_failed; } int err; avopts_ = 0; // open the codec. if ((err = avcodec_open2(avcontext_, avcodec_, &avopts_)) < 0) { char err_message[1000]; memset(err_message, 0, 1000); int err_err = av_strerror(-err, err_message, 1000); std::cerr << "avcodec_open2 Could not open codec: error " << err_err << ": " << err_message << std::endl; goto init_failed; } // alloc image and output buffer video_buffer_size_ = 3000000; video_buffer_ = new uint8_t[video_buffer_size_]; // Initialization of ffmpeg frames. { int rgb_size = avpicture_get_size(PIX_FMT_RGB24, avcontext_->width, avcontext_->height); window_capture_size_ = rgb_size * sizeof(uint8_t); // size for RGB window_capture_ = new unsigned char[window_capture_size_]; window_capture_width_ = avcontext_->width; window_capture_height_ = avcontext_->height; avpicture_fill((AVPicture *)rgbframe_, window_capture_, PIX_FMT_RGB24, avcontext_->width, avcontext_->height); int yuv_size = avpicture_get_size(PIX_FMT_YUV420P, avcontext_->width, avcontext_->height); avpicture_fill((AVPicture *)yuvframe_, new uint8_t[yuv_size * sizeof(uint8_t)], PIX_FMT_YUV420P, avcontext_->width, avcontext_->height); } // Swscale context. swcontext_ = sws_getCachedContext(0, width, height, PIX_FMT_RGB24, width, height, FRAME_FORMAT, SWS_POINT, 0, 0, 0); if(!swcontext_) { std::cerr<< "Cannot initialize the swscale conversion context" << std::endl; goto init_failed; } /* open the output file, if needed */ if (!(outputfmt_->flags & AVFMT_NOFILE)) { #ifdef URL_WRONLY if (avio_open (&fmtcontext_->pb, path_.c_str(), URL_WRONLY) < 0) #else if (avio_open (&fmtcontext_->pb, path_.c_str(), AVIO_FLAG_WRITE) < 0) #endif { std::cerr << "Could not open "<< path_ << std::endl; assert(0 && "Could not open ouput file"); } } /* write the stream header, if any */ avformat_write_header(fmtcontext_, NULL); return; init_failed: init_failed_ = true; if (avcontext_) av_free(avcontext_); if (swcontext_) sws_freeContext(swcontext_); if (yuvframe_) av_free(yuvframe_); if (rgbframe_) av_free(rgbframe_); if (video_buffer_) delete [] video_buffer_; if (window_capture_) delete [] window_capture_; output_.close(); std::cerr << "Video recording disabled." << std::endl; return; }
/* * Audio encoding example */ static void audio_encode_example(const char *filename) { AVCodec *codec; AVCodecContext *c= NULL; AVFrame *frame; AVPacket pkt; int i, j, k, ret, got_output; int buffer_size; FILE *f; uint16_t *samples; float t, tincr; printf("Encode audio file %s\n", filename); /* find the MP2 encoder */ codec = avcodec_find_encoder(AV_CODEC_ID_MP2); if (!codec) { fprintf(stderr, "Codec not found\n"); exit(1); } c = avcodec_alloc_context3(codec); if (!c) { fprintf(stderr, "Could not allocate audio codec context\n"); exit(1); } /* put sample parameters */ c->bit_rate = 64000; /* check that the encoder supports s16 pcm input */ c->sample_fmt = AV_SAMPLE_FMT_S16; if (!check_sample_fmt(codec, c->sample_fmt)) { fprintf(stderr, "Encoder does not support sample format %s", av_get_sample_fmt_name(c->sample_fmt)); exit(1); } /* select other audio parameters supported by the encoder */ c->sample_rate = select_sample_rate(codec); c->channel_layout = select_channel_layout(codec); c->channels = av_get_channel_layout_nb_channels(c->channel_layout); /* open it */ if (avcodec_open2(c, codec, NULL) < 0) { fprintf(stderr, "Could not open codec\n"); exit(1); } f = fopen(filename, "wb"); if (!f) { fprintf(stderr, "Could not open %s\n", filename); exit(1); } /* frame containing input raw audio */ frame = avcodec_alloc_frame(); if (!frame) { fprintf(stderr, "Could not allocate audio frame\n"); exit(1); } frame->nb_samples = c->frame_size; frame->format = c->sample_fmt; frame->channel_layout = c->channel_layout; /* the codec gives us the frame size, in samples, * we calculate the size of the samples buffer in bytes */ buffer_size = av_samples_get_buffer_size(NULL, c->channels, c->frame_size, c->sample_fmt, 0); samples = av_malloc(buffer_size); if (!samples) { fprintf(stderr, "Could not allocate %d bytes for samples buffer\n", buffer_size); exit(1); } /* setup the data pointers in the AVFrame */ ret = avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, (const uint8_t*)samples, buffer_size, 0); if (ret < 0) { fprintf(stderr, "Could not setup audio frame\n"); exit(1); } /* encode a single tone sound */ t = 0; tincr = 2 * M_PI * 440.0 / c->sample_rate; for(i=0;i<200;i++) { av_init_packet(&pkt); pkt.data = NULL; // packet data will be allocated by the encoder pkt.size = 0; for (j = 0; j < c->frame_size; j++) { samples[2*j] = (int)(sin(t) * 10000); for (k = 1; k < c->channels; k++) samples[2*j + k] = samples[2*j]; t += tincr; } /* encode the samples */ ret = avcodec_encode_audio2(c, &pkt, frame, &got_output); if (ret < 0) { fprintf(stderr, "Error encoding audio frame\n"); exit(1); } if (got_output) { fwrite(pkt.data, 1, pkt.size, f); av_free_packet(&pkt); } } /* get the delayed frames */ for (got_output = 1; got_output; i++) { ret = avcodec_encode_audio2(c, &pkt, NULL, &got_output); if (ret < 0) { fprintf(stderr, "Error encoding frame\n"); exit(1); } if (got_output) { fwrite(pkt.data, 1, pkt.size, f); av_free_packet(&pkt); } } fclose(f); av_freep(&samples); avcodec_free_frame(&frame); avcodec_close(c); av_free(c); }
/// Create a video writer object that uses FFMPEG bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, double fps, int width, int height, bool is_color ) { icvInitFFMPEG_internal(); CodecID codec_id = CODEC_ID_NONE; int err, codec_pix_fmt; double bitrate_scale = 1; close(); // check arguments if( !filename ) return false; if(fps <= 0) return false; // we allow frames of odd width or height, but in this case we truncate // the rightmost column/the bottom row. Probably, this should be handled more elegantly, // but some internal functions inside FFMPEG swscale require even width/height. width &= -2; height &= -2; if( width <= 0 || height <= 0 ) return false; /* auto detect the output format from the name and fourcc code. */ #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) fmt = av_guess_format(NULL, filename, NULL); #else fmt = guess_format(NULL, filename, NULL); #endif if (!fmt) return false; /* determine optimal pixel format */ if (is_color) { input_pix_fmt = PIX_FMT_BGR24; } else { input_pix_fmt = PIX_FMT_GRAY8; } /* Lookup codec_id for given fourcc */ #if LIBAVCODEC_VERSION_INT<((51<<16)+(49<<8)+0) if( (codec_id = codec_get_bmp_id( fourcc )) == CODEC_ID_NONE ) return false; #else const struct AVCodecTag * tags[] = { codec_bmp_tags, NULL}; if( (codec_id = av_codec_get_id(tags, fourcc)) == CODEC_ID_NONE ) return false; #endif // alloc memory for context #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) oc = avformat_alloc_context(); #else oc = av_alloc_format_context(); #endif assert (oc); /* set file name */ oc->oformat = fmt; snprintf(oc->filename, sizeof(oc->filename), "%s", filename); /* set some options */ oc->max_delay = (int)(0.7*AV_TIME_BASE); /* This reduces buffer underrun warnings with MPEG */ // set a few optimal pixel formats for lossless codecs of interest.. switch (codec_id) { #if LIBAVCODEC_VERSION_INT>((50<<16)+(1<<8)+0) case CODEC_ID_JPEGLS: // BGR24 or GRAY8 depending on is_color... codec_pix_fmt = input_pix_fmt; break; #endif case CODEC_ID_HUFFYUV: codec_pix_fmt = PIX_FMT_YUV422P; break; case CODEC_ID_MJPEG: case CODEC_ID_LJPEG: codec_pix_fmt = PIX_FMT_YUVJ420P; bitrate_scale = 3; break; case CODEC_ID_RAWVIDEO: codec_pix_fmt = input_pix_fmt == PIX_FMT_GRAY8 || input_pix_fmt == PIX_FMT_GRAY16LE || input_pix_fmt == PIX_FMT_GRAY16BE ? input_pix_fmt : PIX_FMT_YUV420P; break; default: // good for lossy formats, MPEG, etc. codec_pix_fmt = PIX_FMT_YUV420P; break; } double bitrate = MIN(bitrate_scale*fps*width*height, (double)INT_MAX/2); // TODO -- safe to ignore output audio stream? video_st = icv_add_video_stream_FFMPEG(oc, codec_id, width, height, (int)(bitrate + 0.5), fps, codec_pix_fmt); /* set the output parameters (must be done even if no parameters). */ #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) if (av_set_parameters(oc, NULL) < 0) { return false; } #endif #if 0 #if FF_API_DUMP_FORMAT dump_format(oc, 0, filename, 1); #else av_dump_format(oc, 0, filename, 1); #endif #endif /* now that all the parameters are set, we can open the audio and video codecs and allocate the necessary encode buffers */ if (!video_st){ return false; } AVCodec *codec; AVCodecContext *c; #if LIBAVFORMAT_BUILD > 4628 c = (video_st->codec); #else c = &(video_st->codec); #endif c->codec_tag = fourcc; /* find the video encoder */ codec = avcodec_find_encoder(c->codec_id); if (!codec) { fprintf(stderr, "Could not find encoder for codec id %d: %s", c->codec_id, icvFFMPEGErrStr( #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) AVERROR_ENCODER_NOT_FOUND #else -1 #endif )); return false; } int64_t lbit_rate = (int64_t)c->bit_rate; lbit_rate += (bitrate / 2); lbit_rate = std::min(lbit_rate, (int64_t)INT_MAX); c->bit_rate_tolerance = (int)lbit_rate; c->bit_rate = (int)lbit_rate; /* open the codec */ if ((err= #if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) avcodec_open2(c, codec, NULL) #else avcodec_open(c, codec) #endif ) < 0) { fprintf(stderr, "Could not open codec '%s': %s", codec->name, icvFFMPEGErrStr(err)); return false; } outbuf = NULL; if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) { /* allocate output buffer */ /* assume we will never get codec output with more than 4 bytes per pixel... */ outbuf_size = width*height*4; outbuf = (uint8_t *) av_malloc(outbuf_size); } bool need_color_convert; need_color_convert = (c->pix_fmt != input_pix_fmt); /* allocate the encoded raw picture */ picture = icv_alloc_picture_FFMPEG(c->pix_fmt, c->width, c->height, need_color_convert); if (!picture) { return false; } /* if the output format is not our input format, then a temporary picture of the input format is needed too. It is then converted to the required output format */ input_picture = NULL; if ( need_color_convert ) { input_picture = icv_alloc_picture_FFMPEG(input_pix_fmt, c->width, c->height, false); if (!input_picture) { return false; } } /* open the output file, if needed */ if (!(fmt->flags & AVFMT_NOFILE)) { #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0) #else if (avio_open(&oc->pb, filename, AVIO_FLAG_WRITE) < 0) #endif { return false; } } #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0) /* write the stream header, if any */ err=avformat_write_header(oc, NULL); #else err=av_write_header( oc ); #endif if(err < 0) { close(); remove(filename); return false; } frame_width = width; frame_height = height; ok = true; return true; }
// a sample exported function void* get_all_frames_as_tiff(void*) { int ready=0; int video_frame_count=0; int skip=0; int err=0; int strm = -1; int i = 0; int thread_number=0; uint32_t start_frame=0; uint32_t end_frame=0; uint32_t interval=(int)(total_frames/MAX_THREADS); pthread_t id = pthread_self(); for(i=0;i<MAX_THREADS;i++) { if(pthread_equal(id,tid[i])) { start_frame=interval*i; if(i==MAX_THREADS-1) end_frame=total_frames; else end_frame=interval*(i+1); thread_number=i; break; } } ::AVFormatContext * ctx = NULL; AVCodec * codec = NULL; AVCodecContext * codecCtx = NULL; i=0; err = avformat_open_input(&ctx, video_file_name, NULL, NULL); CHECK_ERR(err); err = avformat_find_stream_info(ctx,NULL); CHECK_ERR(err); strm = av_find_best_stream(ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0); codecCtx = ctx->streams[strm]->codec; //printf("%d",ctx->streams[strm]->nb_frames); err = avcodec_open2(codecCtx, codec, NULL); CHECK_ERR(err); for(i=0;i<start_frame;i++) { AVPacket pkt; av_init_packet(&pkt); err = av_read_frame(ctx, &pkt); av_free_packet(&pkt); CHECK_ERR(err); video_frame_count++; } while (video_frame_count<end_frame) { AVPacket pkt; av_init_packet(&pkt); err = av_read_frame(ctx, &pkt); CHECK_ERR(err); if (pkt.stream_index == strm) { int got = 0; AVFrame * frame = av_frame_alloc(); err = avcodec_decode_video2(codecCtx, frame, &got, &pkt); CHECK_ERR(err); if (got) { AVCodec *outCodec = avcodec_find_encoder(AV_CODEC_ID_TIFF); AVCodecContext *outCodecCtx = avcodec_alloc_context3(outCodec); if (!codecCtx) return NULL; outCodecCtx->width = codecCtx->width; outCodecCtx->height = codecCtx->height; outCodecCtx->pix_fmt = codecCtx->pix_fmt; outCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO; outCodecCtx->time_base.num = codecCtx->time_base.num; outCodecCtx->time_base.den = codecCtx->time_base.den; if (!outCodec || avcodec_open2(outCodecCtx, outCodec, NULL) < 0) return NULL; AVPacket outPacket; av_init_packet(&outPacket); outPacket.size = 0; outPacket.data = NULL; int gotFrame = 0; int ret = avcodec_encode_video2(outCodecCtx, &outPacket, frame, &gotFrame); //printf("here"); if (ret >= 0 && gotFrame) { tiff_data_size_array[video_frame_count]=outPacket.size; tiff_data_array[video_frame_count]=(uint8_t*)malloc(outPacket.size*sizeof(uint8_t)); memcpy(tiff_data_array[video_frame_count],outPacket.data,outPacket.size); video_frame_count++; frames_decoded[thread_number]++; } av_free_packet(&outPacket); avcodec_close(outCodecCtx); av_free(outCodecCtx); } av_free_packet(&pkt); av_frame_unref(frame); av_frame_free(&frame); av_free(frame); } } //free(&pkt); avcodec_close(codecCtx); avformat_close_input(&ctx); av_free(ctx); av_free(codec); ctx = NULL; codec = NULL; codecCtx = NULL; pthread_exit(NULL); }
/* add a video output stream to the container */ static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc, CodecID codec_id, int w, int h, int bitrate, double fps, int pixel_format) { AVCodecContext *c; AVStream *st; int frame_rate, frame_rate_base; AVCodec *codec; #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 10, 0) st = avformat_new_stream(oc, 0); #else st = av_new_stream(oc, 0); #endif if (!st) { CV_WARN("Could not allocate stream"); return NULL; } #if LIBAVFORMAT_BUILD > 4628 c = st->codec; #else c = &(st->codec); #endif #if LIBAVFORMAT_BUILD > 4621 c->codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_VIDEO); #else c->codec_id = oc->oformat->video_codec; #endif if(codec_id != CODEC_ID_NONE){ c->codec_id = codec_id; } //if(codec_tag) c->codec_tag=codec_tag; codec = avcodec_find_encoder(c->codec_id); c->codec_type = AVMEDIA_TYPE_VIDEO; /* put sample parameters */ int64_t lbit_rate = (int64_t)bitrate; lbit_rate += (bitrate / 2); lbit_rate = std::min(lbit_rate, (int64_t)INT_MAX); c->bit_rate = lbit_rate; // took advice from // http://ffmpeg-users.933282.n4.nabble.com/warning-clipping-1-dct-coefficients-to-127-127-td934297.html c->qmin = 3; /* resolution must be a multiple of two */ c->width = w; c->height = h; /* time base: this is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented. for fixed-fps content, timebase should be 1/framerate and timestamp increments should be identically 1. */ frame_rate=(int)(fps+0.5); frame_rate_base=1; while (fabs((double)frame_rate/frame_rate_base) - fps > 0.001){ frame_rate_base*=10; frame_rate=(int)(fps*frame_rate_base + 0.5); } #if LIBAVFORMAT_BUILD > 4752 c->time_base.den = frame_rate; c->time_base.num = frame_rate_base; /* adjust time base for supported framerates */ if(codec && codec->supported_framerates){ const AVRational *p= codec->supported_framerates; AVRational req = {frame_rate, frame_rate_base}; const AVRational *best=NULL; AVRational best_error= {INT_MAX, 1}; for(; p->den!=0; p++){ AVRational error= av_sub_q(req, *p); if(error.num <0) error.num *= -1; if(av_cmp_q(error, best_error) < 0){ best_error= error; best= p; } } c->time_base.den= best->num; c->time_base.num= best->den; } #else c->frame_rate = frame_rate; c->frame_rate_base = frame_rate_base; #endif c->gop_size = 12; /* emit one intra frame every twelve frames at most */ c->pix_fmt = (PixelFormat) pixel_format; if (c->codec_id == CODEC_ID_MPEG2VIDEO) { c->max_b_frames = 2; } if (c->codec_id == CODEC_ID_MPEG1VIDEO || c->codec_id == CODEC_ID_MSMPEG4V3){ /* needed to avoid using macroblocks in which some coeffs overflow this doesnt happen with normal video, it just happens here as the motion of the chroma plane doesnt match the luma plane */ /* avoid FFMPEG warning 'clipping 1 dct coefficients...' */ c->mb_decision=2; } #if LIBAVCODEC_VERSION_INT>0x000409 // some formats want stream headers to be seperate if(oc->oformat->flags & AVFMT_GLOBALHEADER) { c->flags |= CODEC_FLAG_GLOBAL_HEADER; } #endif return st; }
RawPixelSource::RawPixelSource(UsageEnvironment& env, Frame* content, int avgBitRate, bool robustSyncing) : FramedSource(env), img_convert_ctx(NULL), content(content), /*encodeBarrier(2),*/ destructing(false), lastPTS(0), robustSyncing(robustSyncing) { gettimeofday(&prevtime, NULL); // If you have a more accurate time - e.g., from an encoder - then use that instead. if (referenceCount == 0) { // Any global initialization of the device would be done here: //%%% TO BE WRITTEN %%% } // Any instance-specific initialization of the device would be done here: ++referenceCount; //myfile = fopen("/Users/tiborgoldschwendt/Desktop/Logs/deviceglxgears.log", "w"); // initialize frame pool for (int i = 0; i < 1; i++) { AVFrame* frame = av_frame_alloc(); if (!frame) { fprintf(stderr, "Could not allocate video frame\n"); exit(1); } frame->format = content->getFormat(); frame->width = content->getWidth(); frame->height = content->getHeight(); /* the image can be allocated by any means and av_image_alloc() is * just the most convenient way if av_malloc() is to be used */ if (av_image_alloc(frame->data, frame->linesize, frame->width, frame->height, content->getFormat(), 32) < 0) { fprintf(stderr, "Could not allocate raw picture buffer\n"); abort(); } framePool.push(frame); } for (int i = 0; i < 1; i++) { AVPacket pkt; av_init_packet(&pkt); pktPool.push(pkt); } // Initialize codec and encoder AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264); if (!codec) { fprintf(stderr, "Codec not found\n"); exit(1); } codecContext = avcodec_alloc_context3(codec); if (!codecContext) { fprintf(stderr, "could not allocate video codec context\n"); exit(1); } /* put sample parameters */ codecContext->bit_rate = avgBitRate; /* resolution must be a multiple of two */ codecContext->width = content->getWidth(); codecContext->height = content->getHeight(); /* frames per second */ codecContext->time_base = av_make_q(1, FPS); codecContext->gop_size = 20; /* emit one intra frame every ten frames */ codecContext->max_b_frames = 0; codecContext->pix_fmt = AV_PIX_FMT_YUV420P; //codecContext->flags |= CODEC_FLAG_GLOBAL_HEADER; av_opt_set(codecContext->priv_data, "preset", PRESET_VAL, 0); av_opt_set(codecContext->priv_data, "tune", TUNE_VAL, 0); av_opt_set(codecContext->priv_data, "slice-max-size", "2000", 0); /* open it */ if (avcodec_open2(codecContext, codec, NULL) < 0) { fprintf(stderr, "could not open codec\n"); exit(1); } // We arrange here for our "deliverFrame" member function to be called // whenever the next frame of data becomes available from the device. // // If the device can be accessed as a readable socket, then one easy way to do this is using a call to // envir().taskScheduler().turnOnBackgroundReadHandling( ... ) // (See examples of this call in the "liveMedia" directory.) // // If, however, the device *cannot* be accessed as a readable socket, then instead we can implement it using 'event triggers': // Create an 'event trigger' for this device (if it hasn't already been done): eventTriggerId = envir().taskScheduler().createEventTrigger(&deliverFrame0); //std::cout << this << ": eventTriggerId: " << eventTriggerId << std::endl; frameContentThread = boost::thread(boost::bind(&RawPixelSource::frameContentLoop, this)); encodeFrameThread = boost::thread(boost::bind(&RawPixelSource::encodeFrameLoop, this)); //eventThread = boost::thread(boost::bind(&RawPixelSource::eventLoop, this)); lastFrameTime = av_gettime(); }
void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int height, int bitrate, double frame_rate ) { /* ffmpeg format matching */ switch(colours) { case ZM_COLOUR_RGB24: { if(subpixelorder == ZM_SUBPIX_ORDER_BGR) { /* BGR subpixel order */ pf = PIX_FMT_BGR24; } else { /* Assume RGB subpixel order */ pf = PIX_FMT_RGB24; } break; } case ZM_COLOUR_RGB32: { if(subpixelorder == ZM_SUBPIX_ORDER_ARGB) { /* ARGB subpixel order */ pf = PIX_FMT_ARGB; } else if(subpixelorder == ZM_SUBPIX_ORDER_ABGR) { /* ABGR subpixel order */ pf = PIX_FMT_ABGR; } else if(subpixelorder == ZM_SUBPIX_ORDER_BGRA) { /* BGRA subpixel order */ pf = PIX_FMT_BGRA; } else { /* Assume RGBA subpixel order */ pf = PIX_FMT_RGBA; } break; } case ZM_COLOUR_GRAY8: pf = PIX_FMT_GRAY8; break; default: Panic("Unexpected colours: %d",colours); break; } if ( strcmp( "rtp", of->name ) == 0 ) { // RTP must have a packet_size. // Not sure what this value should be really... ofc->packet_size = width*height; if ( of->video_codec == AV_CODEC_ID_NONE) { // RTP does not have a default codec in ffmpeg <= 0.8. of->video_codec = AV_CODEC_ID_MPEG4; } } _AVCODECID codec_id = of->video_codec; if ( codec_name ) { AVCodec *a = avcodec_find_encoder_by_name(codec_name); if ( a ) { codec_id = a->id; } else { #if ((LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 11, 0)) && (LIBAVFORMAT_VERSION_MICRO >= 100)) Debug( 1, "Could not find codec \"%s\". Using default \"%s\"", codec_name, avcodec_get_name( codec_id ) ); #else Debug( 1, "Could not find codec \"%s\". Using default \"%d\"", codec_name, codec_id ); #endif } } /* add the video streams using the default format codecs and initialize the codecs */ ost = NULL; if ( codec_id != AV_CODEC_ID_NONE ) { codec = avcodec_find_encoder( codec_id ); if ( !codec ) { #if ((LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 11, 0)) && (LIBAVFORMAT_VERSION_MICRO >= 100)) Fatal( "Could not find encoder for '%s'", avcodec_get_name( codec_id ) ); #else Fatal( "Could not find encoder for '%d'", codec_id ); #endif } #if ((LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 11, 0)) && (LIBAVFORMAT_VERSION_MICRO >= 100)) Debug( 1, "Found encoder for '%s'", avcodec_get_name( codec_id ) ); #else Debug( 1, "Found encoder for '%d'", codec_id ); #endif #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 10, 0) ost = avformat_new_stream( ofc, codec ); #else ost = av_new_stream( ofc, 0 ); #endif if ( !ost ) { Fatal( "Could not alloc stream" ); } ost->id = ofc->nb_streams - 1; Debug( 1, "Allocated stream" ); AVCodecContext *c = ost->codec; c->codec_id = codec->id; c->codec_type = codec->type; c->pix_fmt = strcmp( "mjpeg", ofc->oformat->name ) == 0 ? PIX_FMT_YUVJ422P : PIX_FMT_YUV420P; if ( bitrate <= 100 ) { // Quality based bitrate control (VBR). Scale is 1..31 where 1 is best. // This gets rid of artifacts in the beginning of the movie; and well, even quality. c->flags |= CODEC_FLAG_QSCALE; c->global_quality = FF_QP2LAMBDA * (31 - (31 * (bitrate / 100.0))); } else { c->bit_rate = bitrate; } /* resolution must be a multiple of two */ c->width = width; c->height = height; /* time base: this is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented. for fixed-fps content, timebase should be 1/framerate and timestamp increments should be identically 1. */ c->time_base.den = frame_rate; c->time_base.num = 1; Debug( 1, "Will encode in %d fps.", c->time_base.den ); /* emit one intra frame every second */ c->gop_size = frame_rate; // some formats want stream headers to be seperate if ( of->flags & AVFMT_GLOBALHEADER ) c->flags |= CODEC_FLAG_GLOBAL_HEADER; } else { Fatal( "of->video_codec == AV_CODEC_ID_NONE" ); } }
/* write the header (used two times if non streamed) */ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data_chunk_size) { ASFContext *asf = s->priv_data; AVIOContext *pb = s->pb; AVMetadataTag *tags[5]; int header_size, n, extra_size, extra_size2, wav_extra_size, file_time; int has_title; int metadata_count; AVCodecContext *enc; int64_t header_offset, cur_pos, hpos; int bit_rate; int64_t duration; ff_metadata_conv(&s->metadata, ff_asf_metadata_conv, NULL); tags[0] = av_metadata_get(s->metadata, "title" , NULL, 0); tags[1] = av_metadata_get(s->metadata, "author" , NULL, 0); tags[2] = av_metadata_get(s->metadata, "copyright", NULL, 0); tags[3] = av_metadata_get(s->metadata, "comment" , NULL, 0); tags[4] = av_metadata_get(s->metadata, "rating" , NULL, 0); duration = asf->duration + PREROLL_TIME * 10000; has_title = tags[0] || tags[1] || tags[2] || tags[3] || tags[4]; metadata_count = s->metadata ? s->metadata->count : 0; bit_rate = 0; for(n=0;n<s->nb_streams;n++) { enc = s->streams[n]->codec; av_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */ bit_rate += enc->bit_rate; } if (asf->is_streamed) { put_chunk(s, 0x4824, 0, 0xc00); /* start of stream (length will be patched later) */ } put_guid(pb, &ff_asf_header); avio_wl64(pb, -1); /* header length, will be patched after */ avio_wl32(pb, 3 + has_title + !!metadata_count + s->nb_streams); /* number of chunks in header */ avio_w8(pb, 1); /* ??? */ avio_w8(pb, 2); /* ??? */ /* file header */ header_offset = avio_tell(pb); hpos = put_header(pb, &ff_asf_file_header); put_guid(pb, &ff_asf_my_guid); avio_wl64(pb, file_size); file_time = 0; avio_wl64(pb, unix_to_file_time(file_time)); avio_wl64(pb, asf->nb_packets); /* number of packets */ avio_wl64(pb, duration); /* end time stamp (in 100ns units) */ avio_wl64(pb, asf->duration); /* duration (in 100ns units) */ avio_wl64(pb, PREROLL_TIME); /* start time stamp */ avio_wl32(pb, (asf->is_streamed || !pb->seekable ) ? 3 : 2); /* ??? */ avio_wl32(pb, s->packet_size); /* packet size */ avio_wl32(pb, s->packet_size); /* packet size */ avio_wl32(pb, bit_rate); /* Nominal data rate in bps */ end_header(pb, hpos); /* unknown headers */ hpos = put_header(pb, &ff_asf_head1_guid); put_guid(pb, &ff_asf_head2_guid); avio_wl32(pb, 6); avio_wl16(pb, 0); end_header(pb, hpos); /* title and other infos */ if (has_title) { int len; uint8_t *buf; AVIOContext *dyn_buf; if (avio_open_dyn_buf(&dyn_buf) < 0) return AVERROR(ENOMEM); hpos = put_header(pb, &ff_asf_comment_header); for (n = 0; n < FF_ARRAY_ELEMS(tags); n++) { len = tags[n] ? avio_put_str16le(dyn_buf, tags[n]->value) : 0; avio_wl16(pb, len); } len = avio_close_dyn_buf(dyn_buf, &buf); avio_write(pb, buf, len); av_freep(&buf); end_header(pb, hpos); } if (metadata_count) { AVMetadataTag *tag = NULL; hpos = put_header(pb, &ff_asf_extended_content_header); avio_wl16(pb, metadata_count); while ((tag = av_metadata_get(s->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX))) { put_str16(pb, tag->key); avio_wl16(pb, 0); put_str16(pb, tag->value); } end_header(pb, hpos); } /* stream headers */ for(n=0;n<s->nb_streams;n++) { int64_t es_pos; // ASFStream *stream = &asf->streams[n]; enc = s->streams[n]->codec; asf->streams[n].num = n + 1; asf->streams[n].seq = 0; switch(enc->codec_type) { case AVMEDIA_TYPE_AUDIO: wav_extra_size = 0; extra_size = 18 + wav_extra_size; extra_size2 = 8; break; default: case AVMEDIA_TYPE_VIDEO: wav_extra_size = enc->extradata_size; extra_size = 0x33 + wav_extra_size; extra_size2 = 0; break; } hpos = put_header(pb, &ff_asf_stream_header); if (enc->codec_type == AVMEDIA_TYPE_AUDIO) { put_guid(pb, &ff_asf_audio_stream); put_guid(pb, &ff_asf_audio_conceal_spread); } else { put_guid(pb, &ff_asf_video_stream); put_guid(pb, &ff_asf_video_conceal_none); } avio_wl64(pb, 0); /* ??? */ es_pos = avio_tell(pb); avio_wl32(pb, extra_size); /* wav header len */ avio_wl32(pb, extra_size2); /* additional data len */ avio_wl16(pb, n + 1); /* stream number */ avio_wl32(pb, 0); /* ??? */ if (enc->codec_type == AVMEDIA_TYPE_AUDIO) { /* WAVEFORMATEX header */ int wavsize = ff_put_wav_header(pb, enc); if ((enc->codec_id != CODEC_ID_MP3) && (enc->codec_id != CODEC_ID_MP2) && (enc->codec_id != CODEC_ID_ADPCM_IMA_WAV) && (enc->extradata_size==0)) { wavsize += 2; avio_wl16(pb, 0); } if (wavsize < 0) return -1; if (wavsize != extra_size) { cur_pos = avio_tell(pb); avio_seek(pb, es_pos, SEEK_SET); avio_wl32(pb, wavsize); /* wav header len */ avio_seek(pb, cur_pos, SEEK_SET); } /* ERROR Correction */ avio_w8(pb, 0x01); if(enc->codec_id == CODEC_ID_ADPCM_G726 || !enc->block_align){ avio_wl16(pb, 0x0190); avio_wl16(pb, 0x0190); }else{ avio_wl16(pb, enc->block_align); avio_wl16(pb, enc->block_align); } avio_wl16(pb, 0x01); avio_w8(pb, 0x00); } else { avio_wl32(pb, enc->width); avio_wl32(pb, enc->height); avio_w8(pb, 2); /* ??? */ avio_wl16(pb, 40 + enc->extradata_size); /* size */ /* BITMAPINFOHEADER header */ ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 1); } end_header(pb, hpos); } /* media comments */ hpos = put_header(pb, &ff_asf_codec_comment_header); put_guid(pb, &ff_asf_codec_comment1_header); avio_wl32(pb, s->nb_streams); for(n=0;n<s->nb_streams;n++) { AVCodec *p; const char *desc; int len; uint8_t *buf; AVIOContext *dyn_buf; enc = s->streams[n]->codec; p = avcodec_find_encoder(enc->codec_id); if(enc->codec_type == AVMEDIA_TYPE_AUDIO) avio_wl16(pb, 2); else if(enc->codec_type == AVMEDIA_TYPE_VIDEO) avio_wl16(pb, 1); else avio_wl16(pb, -1); if(enc->codec_id == CODEC_ID_WMAV2) desc = "Windows Media Audio V8"; else desc = p ? p->name : enc->codec_name; if ( avio_open_dyn_buf(&dyn_buf) < 0) return AVERROR(ENOMEM); avio_put_str16le(dyn_buf, desc); len = avio_close_dyn_buf(dyn_buf, &buf); avio_wl16(pb, len / 2); // "number of characters" = length in bytes / 2 avio_write(pb, buf, len); av_freep(&buf); avio_wl16(pb, 0); /* no parameters */ /* id */ if (enc->codec_type == AVMEDIA_TYPE_AUDIO) { avio_wl16(pb, 2); avio_wl16(pb, enc->codec_tag); } else { avio_wl16(pb, 4); avio_wl32(pb, enc->codec_tag); } if(!enc->codec_tag) return -1; } end_header(pb, hpos); /* patch the header size fields */ cur_pos = avio_tell(pb); header_size = cur_pos - header_offset; if (asf->is_streamed) { header_size += 8 + 30 + 50; avio_seek(pb, header_offset - 10 - 30, SEEK_SET); avio_wl16(pb, header_size); avio_seek(pb, header_offset - 2 - 30, SEEK_SET); avio_wl16(pb, header_size); header_size -= 8 + 30 + 50; } header_size += 24 + 6; avio_seek(pb, header_offset - 14, SEEK_SET); avio_wl64(pb, header_size); avio_seek(pb, cur_pos, SEEK_SET); /* movie chunk, followed by packets of packet_size */ asf->data_offset = cur_pos; put_guid(pb, &ff_asf_data_header); avio_wl64(pb, data_chunk_size); put_guid(pb, &ff_asf_my_guid); avio_wl64(pb, asf->nb_packets); /* nb packets */ avio_w8(pb, 1); /* ??? */ avio_w8(pb, 1); /* ??? */ return 0; }
/* * Initialize the encoder for the local source: * - enc_ctx, codec, enc_in_frame are used by ffmpeg for encoding; * - enc_out is used to store the encoded frame (to be sent) * - mtu is used to determine the max size of video fragment * NOTE: we enter here with the video source already open. */ static int video_out_init(struct video_desc *env) { int codec; int size; struct fbuf_t *enc_in; struct video_out_desc *v = &env->out; v->enc_ctx = NULL; v->codec = NULL; v->enc_in_frame = NULL; v->enc_out.data = NULL; codec = map_video_format(v->enc->format, CM_WR); v->codec = avcodec_find_encoder(codec); if (!v->codec) { ast_log(LOG_WARNING, "Cannot find the encoder for format %d\n", codec); return -1; /* error, but nothing to undo yet */ } v->mtu = 1400; /* set it early so the encoder can use it */ /* allocate the input buffer for encoding. * ffmpeg only supports PIX_FMT_YUV420P for the encoding. */ enc_in = &env->enc_in; enc_in->pix_fmt = PIX_FMT_YUV420P; enc_in->size = (enc_in->w * enc_in->h * 3)/2; enc_in->data = ast_calloc(1, enc_in->size); if (!enc_in->data) { ast_log(LOG_WARNING, "Cannot allocate encoder input buffer\n"); return video_out_uninit(env); } /* construct an AVFrame that points into buf_in */ v->enc_in_frame = avcodec_alloc_frame(); if (!v->enc_in_frame) { ast_log(LOG_WARNING, "Unable to allocate the encoding video frame\n"); return video_out_uninit(env); } /* parameters for PIX_FMT_YUV420P */ size = enc_in->w * enc_in->h; v->enc_in_frame->data[0] = enc_in->data; v->enc_in_frame->data[1] = v->enc_in_frame->data[0] + size; v->enc_in_frame->data[2] = v->enc_in_frame->data[1] + size/4; v->enc_in_frame->linesize[0] = enc_in->w; v->enc_in_frame->linesize[1] = enc_in->w/2; v->enc_in_frame->linesize[2] = enc_in->w/2; /* now setup the parameters for the encoder. * XXX should be codec-specific */ { AVCodecContext *enc_ctx = avcodec_alloc_context(); v->enc_ctx = enc_ctx; enc_ctx->pix_fmt = enc_in->pix_fmt; enc_ctx->width = enc_in->w; enc_ctx->height = enc_in->h; /* XXX rtp_callback ? * rtp_mode so ffmpeg inserts as many start codes as possible. */ enc_ctx->rtp_mode = 1; enc_ctx->rtp_payload_size = v->mtu / 2; // mtu/2 enc_ctx->bit_rate = v->bitrate; enc_ctx->bit_rate_tolerance = enc_ctx->bit_rate/2; enc_ctx->qmin = v->qmin; /* should be configured */ enc_ctx->time_base = (AVRational){1, v->fps}; enc_ctx->gop_size = v->fps*5; // emit I frame every 5 seconds v->enc->enc_init(v->enc_ctx); if (avcodec_open(enc_ctx, v->codec) < 0) { ast_log(LOG_WARNING, "Unable to initialize the encoder %d\n", codec); av_free(enc_ctx); v->enc_ctx = NULL; return video_out_uninit(env); } } /* * Allocate enough for the encoded bitstream. As we are compressing, * we hope that the output is never larger than the input size. */ v->enc_out.data = ast_calloc(1, enc_in->size); v->enc_out.size = enc_in->size; v->enc_out.used = 0; return 0; }
bool QVideoEncoder::createFile(QString fileName,unsigned width,unsigned height,unsigned bitrate,unsigned gop,unsigned fps) { // If we had an open video, close it. close(); Width=width; Height=height; Gop=gop; Bitrate=bitrate; if(!isSizeValid()) { printf("Invalid size\n"); return false; } pOutputFormat = ffmpeg::av_guess_format(nullptr, fileName.toStdString().c_str(), nullptr); if (!pOutputFormat) { printf("Could not deduce output format from file extension: using MPEG.\n"); pOutputFormat = ffmpeg::av_guess_format("mpeg", nullptr, nullptr); } pFormatCtx=ffmpeg::avformat_alloc_context(); if(!pFormatCtx) { printf("Error allocating format context\n"); return false; } pFormatCtx->oformat = pOutputFormat; snprintf(pFormatCtx->filename, sizeof(pFormatCtx->filename), "%s", fileName.toStdString().c_str()); // Add the video stream pVideoStream = avformat_new_stream(pFormatCtx,0); if(!pVideoStream ) { printf("Could not allocate stream\n"); return false; } pCodecCtx=pVideoStream->codec; pCodecCtx->codec_id = pOutputFormat->video_codec; pCodecCtx->codec_type = ffmpeg::AVMEDIA_TYPE_VIDEO; pCodecCtx->bit_rate = Bitrate; pCodecCtx->width = getWidth(); pCodecCtx->height = getHeight(); pCodecCtx->time_base.den = fps; pCodecCtx->time_base.num = 1; pCodecCtx->gop_size = Gop; pCodecCtx->pix_fmt = ffmpeg::PIX_FMT_YUV420P; //avcodec_thread_init(pCodecCtx, 10); pCodecCtx->thread_count= 10; //if (c->codec_id == CODEC_ID_MPEG2VIDEO) //{ //c->max_b_frames = 2; // just for testing, we also add B frames //} // some formats want stream headers to be separate if(pFormatCtx->oformat->flags & AVFMT_GLOBALHEADER) pCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER; av_dump_format(pFormatCtx, 0, fileName.toStdString().c_str(), 1); // open_video // find the video encoder pCodec = avcodec_find_encoder(pCodecCtx->codec_id); if (!pCodec) { printf("codec not found\n"); return false; } // open the codec if (avcodec_open2(pCodecCtx, pCodec, nullptr) < 0) { printf("could not open codec\n"); return false; } // Allocate memory for output if(!initOutputBuf()) { printf("Can't allocate memory for output bitstream\n"); return false; } // Allocate the YUV frame if(!initFrame()) { printf("Can't init frame\n"); return false; } if (avio_open(&pFormatCtx->pb, fileName.toStdString().c_str(), AVIO_FLAG_WRITE) < 0) { printf( "Could not open '%s'\n", fileName.toStdString().c_str()); return false; } avformat_write_header(pFormatCtx, nullptr); ok=true; return true; }
static struct proxy_output_ctx * alloc_proxy_output_ffmpeg( struct anim * anim, AVStream * st, int proxy_size, int width, int height, int quality) { struct proxy_output_ctx * rv = MEM_callocN( sizeof(struct proxy_output_ctx), "alloc_proxy_output"); char fname[FILE_MAXDIR+FILE_MAXFILE]; // JPEG requires this width = round_up(width, 8); height = round_up(height, 8); rv->proxy_size = proxy_size; rv->anim = anim; get_proxy_filename(rv->anim, rv->proxy_size, fname, TRUE); BLI_make_existing_file(fname); rv->of = avformat_alloc_context(); rv->of->oformat = av_guess_format("avi", NULL, NULL); BLI_snprintf(rv->of->filename, sizeof(rv->of->filename), "%s", fname); fprintf(stderr, "Starting work on proxy: %s\n", rv->of->filename); rv->st = av_new_stream(rv->of, 0); rv->c = rv->st->codec; rv->c->codec_type = AVMEDIA_TYPE_VIDEO; rv->c->codec_id = CODEC_ID_MJPEG; rv->c->width = width; rv->c->height = height; rv->of->oformat->video_codec = rv->c->codec_id; rv->codec = avcodec_find_encoder(rv->c->codec_id); if (!rv->codec) { fprintf(stderr, "No ffmpeg MJPEG encoder available? " "Proxy not built!\n"); av_free(rv->of); return NULL; } if (rv->codec->pix_fmts) { rv->c->pix_fmt = rv->codec->pix_fmts[0]; } else { rv->c->pix_fmt = PIX_FMT_YUVJ420P; } rv->c->sample_aspect_ratio = rv->st->sample_aspect_ratio = st->codec->sample_aspect_ratio; rv->c->time_base.den = 25; rv->c->time_base.num = 1; rv->st->time_base = rv->c->time_base; if (rv->of->flags & AVFMT_GLOBALHEADER) { rv->c->flags |= CODEC_FLAG_GLOBAL_HEADER; } if (av_set_parameters(rv->of, NULL) < 0) { fprintf(stderr, "Couldn't set output parameters? " "Proxy not built!\n"); av_free(rv->of); return 0; } if (avio_open(&rv->of->pb, fname, AVIO_FLAG_WRITE) < 0) { fprintf(stderr, "Couldn't open outputfile! " "Proxy not built!\n"); av_free(rv->of); return 0; } avcodec_open(rv->c, rv->codec); rv->video_buffersize = 2000000; rv->video_buffer = (uint8_t*)MEM_mallocN( rv->video_buffersize, "FFMPEG video buffer"); rv->orig_height = st->codec->height; if (st->codec->width != width || st->codec->height != height || st->codec->pix_fmt != rv->c->pix_fmt) { rv->frame = avcodec_alloc_frame(); avpicture_fill((AVPicture*) rv->frame, MEM_mallocN(avpicture_get_size( rv->c->pix_fmt, round_up(width, 16), height), "alloc proxy output frame"), rv->c->pix_fmt, round_up(width, 16), height); rv->sws_ctx = sws_getContext( st->codec->width, st->codec->height, st->codec->pix_fmt, width, height, rv->c->pix_fmt, SWS_FAST_BILINEAR | SWS_PRINT_INFO, NULL, NULL, NULL); } av_write_header(rv->of); return rv; }
/* This function opens an mpeg file using the new libavformat method. Both mpeg1 * and mpeg4 are supported. However, if the current ffmpeg version doesn't allow * mpeg1 with non-standard framerate, the open will fail. Timelapse is a special * case and is tested separately. */ struct ffmpeg *ffmpeg_open(char *ffmpeg_video_codec, char *filename, unsigned char *y, unsigned char *u, unsigned char *v, int width, int height, int rate, int bps, int vbr) { AVCodecContext *c; AVCodec *codec; struct ffmpeg *ffmpeg; int is_mpeg1; /* Allocate space for our ffmpeg structure. This structure contains all the * codec and image information we need to generate movies. * FIXME when motion exits we should close the movie to ensure that * ffmpeg is freed. */ ffmpeg = mymalloc(sizeof(struct ffmpeg)); memset(ffmpeg, 0, sizeof(struct ffmpeg)); ffmpeg->vbr = vbr; /* store codec name in ffmpeg->codec, with buffer overflow check */ snprintf(ffmpeg->codec, sizeof(ffmpeg->codec), "%s", ffmpeg_video_codec); /* allocation the output media context */ ffmpeg->oc = av_mallocz(sizeof(AVFormatContext)); if (!ffmpeg->oc) { motion_log(LOG_ERR, 1, "Memory error while allocating output media context"); ffmpeg_cleanups(ffmpeg); return NULL; } /* Setup output format */ ffmpeg->oc->oformat = get_oformat(ffmpeg_video_codec, filename); if (!ffmpeg->oc->oformat) { ffmpeg_cleanups(ffmpeg); return NULL; } snprintf(ffmpeg->oc->filename, sizeof(ffmpeg->oc->filename), "%s", filename); /* Create a new video stream and initialize the codecs */ ffmpeg->video_st = NULL; if (ffmpeg->oc->oformat->video_codec != CODEC_ID_NONE) { ffmpeg->video_st = av_new_stream(ffmpeg->oc, 0); if (!ffmpeg->video_st) { motion_log(LOG_ERR, 1, "av_new_stream - could not alloc stream"); ffmpeg_cleanups(ffmpeg); return NULL; } } else { /* We did not get a proper video codec. */ motion_log(LOG_ERR, 0, "Failed to obtain a proper video codec"); ffmpeg_cleanups(ffmpeg); return NULL; } ffmpeg->c = c = AVSTREAM_CODEC_PTR(ffmpeg->video_st); c->codec_id = ffmpeg->oc->oformat->video_codec; c->codec_type = CODEC_TYPE_VIDEO; is_mpeg1 = c->codec_id == CODEC_ID_MPEG1VIDEO; if (strcmp(ffmpeg_video_codec, "ffv1") == 0) c->strict_std_compliance = -2; /* Uncomment to allow non-standard framerates. */ //c->strict_std_compliance = -1; /* Set default parameters */ c->bit_rate = bps; c->width = width; c->height = height; #if LIBAVCODEC_BUILD >= 4754 /* frame rate = 1/time_base, so we set 1/rate, not rate/1 */ c->time_base.num = 1; c->time_base.den = rate; #else c->frame_rate = rate; c->frame_rate_base = 1; #endif /* LIBAVCODEC_BUILD >= 4754 */ if (debug_level >= CAMERA_DEBUG) motion_log(LOG_DEBUG, 0, "%s FPS %d",__FUNCTION__,rate); if (vbr) c->flags |= CODEC_FLAG_QSCALE; /* Set codec specific parameters. */ /* set intra frame distance in frames depending on codec */ c->gop_size = is_mpeg1 ? 10 : 12; /* some formats want stream headers to be separate */ if (!strcmp(ffmpeg->oc->oformat->name, "mp4") || !strcmp(ffmpeg->oc->oformat->name, "mov") || !strcmp(ffmpeg->oc->oformat->name, "3gp")) { c->flags |= CODEC_FLAG_GLOBAL_HEADER; } /* set the output parameters (must be done even if no parameters). */ if (av_set_parameters(ffmpeg->oc, NULL) < 0) { motion_log(LOG_ERR, 0, "ffmpeg av_set_parameters error: Invalid output format parameters"); ffmpeg_cleanups(ffmpeg); return NULL; } /* Dump the format settings. This shows how the various streams relate to each other */ //dump_format(ffmpeg->oc, 0, filename, 1); /* Now that all the parameters are set, we can open the video codec and allocate the necessary encode buffers */ codec = avcodec_find_encoder(c->codec_id); if (!codec) { motion_log(LOG_ERR, 1, "Codec not found"); ffmpeg_cleanups(ffmpeg); return NULL; } /* Set the picture format - need in ffmpeg starting round April-May 2005 */ c->pix_fmt = PIX_FMT_YUV420P; /* Get a mutex lock. */ pthread_mutex_lock(&global_lock); /* open the codec */ if (avcodec_open(c, codec) < 0) { /* Release the lock. */ pthread_mutex_unlock(&global_lock); motion_log(LOG_ERR, 1, "avcodec_open - could not open codec"); ffmpeg_cleanups(ffmpeg); return NULL; } /* Release the lock. */ pthread_mutex_unlock(&global_lock); ffmpeg->video_outbuf = NULL; if (!(ffmpeg->oc->oformat->flags & AVFMT_RAWPICTURE)) { /* allocate output buffer */ /* XXX: API change will be done */ /* ffmpeg->video_outbuf_size = 20000; */ ffmpeg->video_outbuf_size = ffmpeg->c->width * 256; ffmpeg->video_outbuf = mymalloc(ffmpeg->video_outbuf_size); } /* allocate the encoded raw picture */ ffmpeg->picture = avcodec_alloc_frame(); if (!ffmpeg->picture) { motion_log(LOG_ERR, 1, "avcodec_alloc_frame - could not alloc frame"); ffmpeg_cleanups(ffmpeg); return NULL; } /* set variable bitrate if requested */ if (ffmpeg->vbr) ffmpeg->picture->quality = ffmpeg->vbr; /* set the frame data */ ffmpeg->picture->data[0] = y; ffmpeg->picture->data[1] = u; ffmpeg->picture->data[2] = v; ffmpeg->picture->linesize[0] = ffmpeg->c->width; ffmpeg->picture->linesize[1] = ffmpeg->c->width / 2; ffmpeg->picture->linesize[2] = ffmpeg->c->width / 2; /* open the output file, if needed */ if (!(ffmpeg->oc->oformat->flags & AVFMT_NOFILE)) { char file_proto[256]; /* Use append file protocol for mpeg1, to get the append behavior from * url_fopen, but no protocol (=> default) for other codecs. */ if (is_mpeg1) snprintf(file_proto, sizeof(file_proto), APPEND_PROTO ":%s", filename); else snprintf(file_proto, sizeof(file_proto), "%s", filename); if (url_fopen(&ffmpeg->oc->pb, file_proto, URL_WRONLY) < 0) { /* path did not exist? */ if (errno == ENOENT) { /* create path for file (don't use file_proto)... */ if (create_path(filename) == -1) { ffmpeg_cleanups(ffmpeg); return NULL; } /* and retry opening the file (use file_proto) */ if (url_fopen(&ffmpeg->oc->pb, file_proto, URL_WRONLY) < 0) { motion_log(LOG_ERR, 1, "url_fopen - error opening file %s",filename); ffmpeg_cleanups(ffmpeg); return NULL; } /* Permission denied */ } else if (errno == EACCES) { motion_log(LOG_ERR, 1, "url_fopen - error opening file %s" " ... check access rights to target directory", filename); ffmpeg_cleanups(ffmpeg); return NULL; } else { motion_log(LOG_ERR, 1, "Error opening file %s", filename); ffmpeg_cleanups(ffmpeg); return NULL; } } } /* write the stream header, if any */ av_write_header(ffmpeg->oc); return ffmpeg; }
/* Add an output stream. */ static void add_stream(OutputStream *ost, AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id) { AVCodecContext *c; int i; /* find the encoder */ *codec = avcodec_find_encoder(codec_id); if (!(*codec)) { fprintf(stderr, "Could not find encoder for '%s'\n", avcodec_get_name(codec_id)); exit(1); } ost->st = avformat_new_stream(oc, *codec); if (!ost->st) { fprintf(stderr, "Could not allocate stream\n"); exit(1); } ost->st->id = oc->nb_streams-1; c = ost->st->codec; switch ((*codec)->type) { case AVMEDIA_TYPE_AUDIO: c->sample_fmt = (*codec)->sample_fmts ? (*codec)->sample_fmts[0] : AV_SAMPLE_FMT_FLTP; c->bit_rate = 64000; c->sample_rate = 44100; if ((*codec)->supported_samplerates) { c->sample_rate = (*codec)->supported_samplerates[0]; for (i = 0; (*codec)->supported_samplerates[i]; i++) { if ((*codec)->supported_samplerates[i] == 44100) c->sample_rate = 44100; } } c->channels = av_get_channel_layout_nb_channels(c->channel_layout); c->channel_layout = AV_CH_LAYOUT_STEREO; if ((*codec)->channel_layouts) { c->channel_layout = (*codec)->channel_layouts[0]; for (i = 0; (*codec)->channel_layouts[i]; i++) { if ((*codec)->channel_layouts[i] == AV_CH_LAYOUT_STEREO) c->channel_layout = AV_CH_LAYOUT_STEREO; } } c->channels = av_get_channel_layout_nb_channels(c->channel_layout); ost->st->time_base = (AVRational) { 1, c->sample_rate }; break; case AVMEDIA_TYPE_VIDEO: c->codec_id = codec_id; c->bit_rate = 400000; /* Resolution must be a multiple of two. */ c->width = 352; c->height = 288; /* timebase: This is the fundamental unit of time (in seconds) in terms * of which frame timestamps are represented. For fixed-fps content, * timebase should be 1/framerate and timestamp increments should be * identical to 1. */ ost->st->time_base = (AVRational) { 1, STREAM_FRAME_RATE }; c->time_base = ost->st->time_base; c->gop_size = 12; /* emit one intra frame every twelve frames at most */ c->pix_fmt = STREAM_PIX_FMT; if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) { /* just for testing, we also add B frames */ c->max_b_frames = 2; } if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) { /* Needed to avoid using macroblocks in which some coeffs overflow. * This does not happen with normal video, it just happens here as * the motion of the chroma plane does not match the luma plane. */ c->mb_decision = 2; } break; default: break; } /* Some formats want stream headers to be separate. */ if (oc->oformat->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; }
static void png_mkdir(char *buf, int verbose) { struct stat stat_p; #ifndef __MINGW32__ if ( mkdir(buf, 0755) < 0 ) { #else if ( mkdir(buf) < 0 ) { #endif switch (errno) { /* use switch in case other errors need to be caught and handled in the future */ case EEXIST: if ( stat(buf, &stat_p ) < 0 ) { mp_msg(MSGT_VO, MSGL_ERR, "%s: %s: %s\n", info.short_name, MSGTR_VO_GenericError, strerror(errno) ); mp_msg(MSGT_VO, MSGL_ERR, "%s: %s %s\n", info.short_name, MSGTR_VO_UnableToAccess,buf); exit_player(EXIT_ERROR); } if ( !S_ISDIR(stat_p.st_mode) ) { mp_msg(MSGT_VO, MSGL_ERR, "%s: %s %s\n", info.short_name, buf, MSGTR_VO_ExistsButNoDirectory); exit_player(EXIT_ERROR); } if ( !(stat_p.st_mode & S_IWUSR) ) { mp_msg(MSGT_VO, MSGL_ERR, "%s: %s - %s\n", info.short_name, buf, MSGTR_VO_DirExistsButNotWritable); exit_player(EXIT_ERROR); } mp_msg(MSGT_VO, MSGL_INFO, "%s: %s: %s\n", info.short_name, MSGTR_VO_OutputDirectory, buf); break; default: mp_msg(MSGT_VO, MSGL_ERR, "%s: %s: %s\n", info.short_name, MSGTR_VO_GenericError, strerror(errno) ); mp_msg(MSGT_VO, MSGL_ERR, "%s: %s - %s\n", info.short_name, buf, MSGTR_VO_CantCreateDirectory); exit_player(EXIT_ERROR); } /* end switch */ } else if ( verbose ) { mp_msg(MSGT_VO, MSGL_INFO, "%s: %s - %s\n", info.short_name, buf, MSGTR_VO_DirectoryCreateSuccess); } /* end if */ } static int config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format) { char buf[BUFLENGTH]; if(z_compression == 0) { mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_PNG_Warning1); mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_PNG_Warning2); mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_PNG_Warning3); } snprintf(buf, BUFLENGTH, "%s", png_outdir); png_mkdir(buf, 1); mp_msg(MSGT_VO,MSGL_DBG2, "PNG Compression level %i\n", z_compression); if (avctx && png_format != format) { avcodec_close(avctx); av_freep(&avctx); } if (!avctx) { avctx = avcodec_alloc_context3(NULL); avctx->compression_level = z_compression; avctx->pix_fmt = imgfmt2pixfmt(format); avctx->width = width; avctx->height = height; if (avcodec_open2(avctx, avcodec_find_encoder(AV_CODEC_ID_PNG), NULL) < 0) { uninit(); return -1; } png_format = format; } return 0; }
void VideoStream::OpenStream() { /* now that all the parameters are set, we can open the video codecs and allocate the necessary encode buffers */ if ( ost ) { #if ZM_FFMPEG_SVN AVCodecContext *c = ost->codec; #else AVCodecContext *c = &ost->codec; #endif /* find the video encoder */ AVCodec *codec = avcodec_find_encoder(c->codec_id); if ( !codec ) { Panic( "codec not found" ); } /* open the codec */ #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 7, 0) if ( avcodec_open(c, codec) < 0 ) #else if ( avcodec_open2(c, codec, 0) < 0 ) #endif { Panic( "Could not open codec" ); } /* allocate the encoded raw picture */ opicture = avcodec_alloc_frame(); if ( !opicture ) { Panic( "Could not allocate opicture" ); } int size = avpicture_get_size( c->pix_fmt, c->width, c->height); uint8_t *opicture_buf = (uint8_t *)av_malloc(size); if ( !opicture_buf ) { av_free(opicture); Panic( "Could not allocate opicture" ); } avpicture_fill( (AVPicture *)opicture, opicture_buf, c->pix_fmt, c->width, c->height ); /* if the output format is not identical to the input format, then a temporary picture is needed too. It is then converted to the required output format */ tmp_opicture = NULL; if ( c->pix_fmt != pf ) { tmp_opicture = avcodec_alloc_frame(); if ( !tmp_opicture ) { Panic( "Could not allocate temporary opicture" ); } int size = avpicture_get_size( pf, c->width, c->height); uint8_t *tmp_opicture_buf = (uint8_t *)av_malloc(size); if (!tmp_opicture_buf) { av_free( tmp_opicture ); Panic( "Could not allocate temporary opicture" ); } avpicture_fill( (AVPicture *)tmp_opicture, tmp_opicture_buf, pf, c->width, c->height ); } } /* open the output file, if needed */ if ( !(of->flags & AVFMT_NOFILE) ) { #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1) if ( avio_open(&ofc->pb, filename, AVIO_FLAG_WRITE) < 0 ) #else if ( url_fopen(&ofc->pb, filename, AVIO_FLAG_WRITE) < 0 ) #endif { Fatal( "Could not open '%s'", filename ); } } video_outbuf = NULL; if ( !(ofc->oformat->flags & AVFMT_RAWPICTURE) ) { /* allocate output buffer */ /* XXX: API change will be done */ video_outbuf_size = 200000; video_outbuf = (uint8_t *)malloc(video_outbuf_size); } /* write the stream header, if any */ #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0) av_write_header(ofc); #else avformat_write_header(ofc, NULL); #endif }