1 #include "VideoSink_FFmpeg.hh"
2 #include <Base/Image/ImageIO.hh>
3 #include <Base/Image/ImageConvert.hh>
4 #include <Filter/Rescale.hh>
36 codecId_ = CODEC_ID_MPEG1VIDEO;
63 sprintf(str,
"%f", fps);
64 av_parse_video_frame_rate(&fps_, str);
79 maxBFrames_ = maxBFrames;
95 AVOutputFormat *oformat;
106 if (!override_ && url_exist(oc->filename)) {
107 errMsg_ =
"Output file already exists.";
112 oformat = av_guess_format(NULL, filename.c_str(), NULL);
114 errMsg_ =
"Unknown file extension";
119 if (
realtime_ && (strcmp(oformat->name,
"matroska") && strcmp(oformat->name,
"flv"))) {
120 errMsg_ =
"Realtime encoding is only available for .mkv and .flv files";
125 codec = avcodec_find_encoder(codecId_);
126 if (!codec || codec->type != CODEC_TYPE_VIDEO) {
127 errMsg_ =
"Unknown video encoder";
132 if (width_ % 2 || height_ % 2) {
133 errMsg_ =
"Resolution must be a multiple of two";
140 oc = avformat_alloc_context();
142 errMsg_ =
"Not enough memory to allocate format context";
147 oc->oformat = oformat;
148 av_strlcpy(oc->filename, filename.c_str(),
sizeof(oc->filename));
149 oc->preload = (int)(0.5 * AV_TIME_BASE);
150 oc->max_delay = (int)(0.7 * AV_TIME_BASE);
151 oc->flags |= AVFMT_FLAG_NONBLOCK;
154 oc->timestamp = av_gettime();
161 timeinfo = localtime(&rawtime);
162 strftime(datestr, 20,
"%Y-%m-%d %H:%M:%S", timeinfo);
163 av_metadata_set2(&oc->metadata,
"date", datestr, 0);
166 st = av_new_stream(oc, codec->id);
168 errMsg_ =
"Could not create video stream";
173 avcodec_get_context_defaults2(st->codec, AVMEDIA_TYPE_VIDEO);
177 c->codec_id = codec->id;
178 c->codec_type = CODEC_TYPE_VIDEO;
179 c->codec_tag = av_codec_get_tag(oformat->codec_tag, c->codec_id);
182 c->gop_size = gopSize_;
183 c->bit_rate = bitrate_;
184 c->max_b_frames = maxBFrames_;
192 if (codec && codec->supported_framerates)
193 fps_ = codec->supported_framerates[av_find_nearest_q_idx(fps_, codec->supported_framerates)];
194 c->time_base.den = st->r_frame_rate.num = fps_.num;
195 c->time_base.num = st->r_frame_rate.den = fps_.den;
196 st->time_base.den =
realtime_ ? 1000 : fps_.num;
197 st->time_base.num =
realtime_ ? 1: fps_.den;
198 av_metadata_set2(&st->metadata,
"date", datestr, 0);
202 case CODEC_ID_HUFFYUV:
203 c->pix_fmt = PIX_FMT_YUV422P;
207 c->pix_fmt = PIX_FMT_YUVJ420P;
211 c->pix_fmt = PIX_FMT_YUV420P;
216 st->sample_aspect_ratio = c->sample_aspect_ratio;
219 if (oc->oformat->flags & AVFMT_GLOBALHEADER)
220 c->flags |= CODEC_FLAG_GLOBAL_HEADER;
223 if (av_set_parameters(oc, NULL) < 0) {
224 errMsg_ =
"invalid encoding parameters";
229 if (avcodec_open(c, codec) < 0) {
230 errMsg_ =
"Could not open codec";
235 if (url_fopen(&oc->pb, oc->filename, URL_WRONLY) < 0) {
236 errMsg_ =
"Could not open output file";
241 bufferSize_ = c->width * c->height * 3;
242 pBuffer_ = (uint8_t *) av_malloc(bufferSize_);
244 errMsg_ =
"Could not allocate output buffer";
249 pPict_ = avcodec_alloc_frame();
251 errMsg_ =
"Could not allocate raw picture";
256 int size = avpicture_get_size(c->pix_fmt, c->width, c->height);
257 pPictBuffer_ = (uint8_t *) av_malloc(size);
259 errMsg_ =
"Could not allocate raw picture buffer";
264 if (!avpicture_fill((AVPicture *) pPict_, pPictBuffer_, c->pix_fmt, c->width, c->height)) {
265 errMsg_ =
"Could not fill raw picture buffer";
270 pInputPict_ = avcodec_alloc_frame();
272 errMsg_ =
"Could not allocate input picture";
277 if (av_write_header(oc) < 0) {
278 errMsg_ =
"Could not write header";
283 dump_format(oc, 0, oc->filename, 1);
292 AVFormatContext *oc = pFormatCtx_;
294 AVCodecContext *c = NULL;
305 av_write_trailer(oc);
317 av_free(pInputPict_);
332 errMsg_ =
"Video output file is not opened";
336 AVFormatContext *oc = pFormatCtx_;
337 AVStream *st = oc->streams[0];
338 AVCodecContext *c = st->codec;
341 enum PixelFormat inputPixFmt;
345 if (!oc->start_time_realtime) {
346 oc->start_time_realtime = av_gettime();
350 delta = av_gettime() - oc->start_time_realtime;
351 pts_ = delta * (float) st->time_base.den / (
float) st->time_base.num / (float) 1000000;
361 if(ret != 0) { BIASERR(
"Could not ScaleShift float images!");
return -1;}
364 if(ret != 0){ BIASERR(
"Could not convert Storagetype of image!");
return -1;}
381 if (inputPixFmt == PIX_FMT_NONE) {
384 if(ret != 0) BIASERR(
"Could not convert image to rgb!");
388 if (inputPixFmt == PIX_FMT_NONE) {
389 errMsg_ =
"Input color model not supported";
394 if (workImg.
GetSize() != (unsigned) avpicture_get_size(inputPixFmt, c->width, c->height)) {
396 if(workImg.
GetSize() >(unsigned) avpicture_get_size(inputPixFmt, c->width, c->height)){
398 ret = rescaler.
Downsample(tmpImg,workImg,c->width,c->height);
399 if(ret != 0) BIASERR(
"Could not downsample image to requested size!");
403 ret = rescaler.
Upsample(tmpImg,workImg,c->width,c->height);
404 if(ret != 0) BIASERR(
"Could not upsample image to requested size!");
407 if (workImg.
GetSize() != (unsigned) avpicture_get_size(inputPixFmt, c->width, c->height)) {
410 <<
"does not match video output size:"<<c->width<<
"x"<<c->height;
416 avpicture_fill((AVPicture *) pInputPict_, (uint8_t *) workImg.
GetImageData(), inputPixFmt, c->width, c->height);
419 pSwsCtx_ = sws_getCachedContext(pSwsCtx_, workImg.
GetWidth(), workImg.
GetHeight(), inputPixFmt, c->width, c->height, c->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);
421 errMsg_ =
"Could not find color convert context";
426 if (sws_scale(pSwsCtx_, pInputPict_->data, pInputPict_->linesize, 0, c->height, pPict_->data, pPict_->linesize) < 0) {
427 errMsg_ =
"Could not convert color of input picture";
432 av_init_packet(&pkt);
433 pkt.stream_index = st->index;
435 if (oc->oformat->flags & AVFMT_RAWPICTURE) {
437 pkt.data = (uint8_t *) pPict_;
438 pkt.size =
sizeof(AVPicture);
439 pkt.pts = av_rescale_q(pts_++, c->time_base, st->time_base);
440 pkt.flags |= AV_PKT_FLAG_KEY;
443 ret = av_interleaved_write_frame(oc, &pkt);
445 errMsg_ =
"Could not write raw frame";
451 pPict_->quality = st->quality;
456 ret = avcodec_encode_video(c, pBuffer_, bufferSize_, pPict_);
458 errMsg_ =
"Video encoding failed";
468 if (!
realtime_ && c->coded_frame->pts != (
unsigned) AV_NOPTS_VALUE)
469 pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
471 pkt.pts = c->coded_frame->pts;
472 if (c->coded_frame->key_frame)
473 pkt.flags |= AV_PKT_FLAG_KEY;
476 ret = av_interleaved_write_frame(oc, &pkt);
478 errMsg_ =
"Could not write frame";
491 return AddFrame(image);
497 vector<string>::iterator f;
498 for (f = filenames.begin(); f != filenames.end() && ret == 0; ++f)
505 switch (colorModel) {
517 default:
return PIX_FMT_NONE;
EColorModel
These are the most often used color models.
YUYV422, 2 channels, full luminance Y, subsampled half U,V.
void SetEncoder(enum CodecID codecId)
Set encoder.
void SetSize(int width, int height)
Set frame size of video.
void SetRealtime(bool realtime)
Set realtime mode.
void Init_()
Called by constructor to init variables.
void SetFPS(float fps)
Set framerate in frames per second.
int ScaleShiftBetween(double Min, double Max)
scales and shifts image so afterwards every pixel has a value between Min and Max ...
int AddFrames(std::vector< std::string > filenames)
Load each Image from a list of files and add them to the video output file.
int Close()
Close the video output file, write remaining frames and clean up.
void SetMaxBFrames(int maxBFrames)
Set maximal number of bidirectional frames.
YUV411, 2 channles, full luminance, 1 U, 1 V.
int AddFrame(const ImageBase &image)
Add an Image to the stream and write it to the video output file.
void SetColorModel(EColorModel Model)
int Downsample(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
generic downsample function.
unsigned int GetWidth() const
enum PixelFormat GetPixelFormat_(enum ImageBase::EColorModel colorModel)
Get the pixel format from a given color model.
void SetGopSize(int gopSize)
Set the gop size of the video stream.
YUV420P, 2 channels, full luminance Y, 1 U, 1 V. Y, U and V are grouped together for better compressi...
color values, 3 channels, order: blue,green,red
void SetDefaults()
Reset all user parameters to default values.
CM_YUV444, 3 channels, all channels have full data.
static int ConvertST(const BIAS::ImageBase &source, BIAS::ImageBase &dest, ImageBase::EStorageType targetST)
Function to convert the storage type of images e.g.
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
color values, 3 channels, order: red,green,blue
unsigned int GetHeight() const
int Upsample(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
generic upsample function
~VideoSink_FFmpeg()
Clean up.
UYVY422, 2 channels, full luminance Y, subsampled half U,V inverse order.
void SetBitrate(int bitrate)
Set bitrate in bits per second.
const StorageType * GetImageData() const
overloaded GetImageData() from ImageBase
int Open(std::string filename)
Open a file for video output and init the codec.
RGBA, 4 channels, order: red,green,blue,alpha.
enum EColorModel GetColorModel() const
static int Load(const std::string &FileName, ImageBase &img)
first tries a call to Read MIP image and if that fails, tries to Import Image with all other availabl...
invalid (not set) image format
enum EStorageType GetStorageType() const
VideoSink_FFmpeg()
Standard constructor.
(8bit) unsigned char image storage type
GreyA, 2 channels, grey plus Alpha.
void SetOverride(bool override)
Set if the output file should be overridden if it already exists.
This is the base class for images in BIAS.
static int ToRGB(const Image< StorageType > &source, Image< StorageType > &dest)
Create a RGB converted copy of source image in this.
unsigned int GetSize() const
returns the image size in bytes = count - NOT the dimension DEPRECATED Please use GetSizeByte instead...
BGRA color values, 4 channels, order: blue,green,red,alpha.