Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
VideoSink_FFmpeg.cpp
1 #include "VideoSink_FFmpeg.hh"
2 #include <Base/Image/ImageIO.hh>
3 #include <Base/Image/ImageConvert.hh>
4 #include <Filter/Rescale.hh>
5 #include <time.h>
6 
7 using namespace BIAS;
8 using namespace std;
9 
11 {
12  av_register_all();
13  Init_();
14  SetDefaults();
15 }
16 
18 {
19  Close();
20 }
21 
23  pFormatCtx_ = NULL;
24  pInputPict_ = NULL;
25  pSwsCtx_ = NULL;
26  pPict_ = NULL;
27  pPictBuffer_ = NULL;
28  pBuffer_ = NULL;
29  bufferSize_ = 0;
30  pts_ = 0;
31  errMsg_ = "";
32 }
33 
35 {
36  codecId_ = CODEC_ID_MPEG1VIDEO;
37  width_ = 352;
38  height_ = 288;
39  fps_.num = 25;
40  fps_.den = 1;
41  bitrate_ = 1000000;
42  gopSize_ = 12;
43  maxBFrames_ = 0;
44  realtime_ = false;
45  override_ = true;
46 }
47 
48 void VideoSink_FFmpeg::SetEncoder(enum CodecID codecId)
49 {
50  codecId_ = codecId;
51 }
52 
53 void VideoSink_FFmpeg::SetSize(int width, int height)
54 {
55  width_ = width;
56  height_ = height;
57 }
58 
59 void VideoSink_FFmpeg::SetFPS(float fps)
60 {
61  //fps_ = av_d2q(fps, AV_TIME_BASE);
62  char str[32];
63  sprintf(str, "%f", fps);
64  av_parse_video_frame_rate(&fps_, str);
65 }
66 
68 {
69  bitrate_ = bitrate;
70 }
71 
73 {
74  gopSize_ = gopSize;
75 }
76 
77 void VideoSink_FFmpeg::SetMaxBFrames(int maxBFrames)
78 {
79  maxBFrames_ = maxBFrames;
80 }
81 
82 void VideoSink_FFmpeg::SetRealtime(bool realtime)
83 {
84  realtime_ = realtime;
85 }
86 
87 void VideoSink_FFmpeg::SetOverride(bool override)
88 {
89  override_ = override;
90 }
91 
92 int VideoSink_FFmpeg::Open(string filename)
93 {
94  AVFormatContext *oc;
95  AVOutputFormat *oformat;
96  AVStream *st;
97  AVCodecContext *c;
98  AVCodec *codec;
99 
100  // Close video file if already opened
101  Close();
102 
103  // Check parameters
104 
105  // Check if output file already exists
106  if (!override_ && url_exist(oc->filename)) {
107  errMsg_ = "Output file already exists.";
108  return -1;
109  }
110 
111  // Get output format from filename extension
112  oformat = av_guess_format(NULL, filename.c_str(), NULL);
113  if (!oformat) {
114  errMsg_ = "Unknown file extension";
115  return -1;
116  }
117 
118  // Check output format for realtime support
119  if (realtime_ && (strcmp(oformat->name, "matroska") && strcmp(oformat->name, "flv"))) {
120  errMsg_ = "Realtime encoding is only available for .mkv and .flv files";
121  return -1;
122  }
123 
124  // Select video encoder
125  codec = avcodec_find_encoder(codecId_);
126  if (!codec || codec->type != CODEC_TYPE_VIDEO) {
127  errMsg_ = "Unknown video encoder";
128  return -1;
129  }
130 
131  // Width and hight must be a multiple of two
132  if (width_ % 2 || height_ % 2) {
133  errMsg_ = "Resolution must be a multiple of two";
134  return -1;
135  }
136 
137  // Now set up the real stuff
138 
139  // Allocate format context
140  oc = avformat_alloc_context();
141  if (!oc) {
142  errMsg_ = "Not enough memory to allocate format context";
143  return -1;
144  }
145 
146  // Set format parameters
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;
152 
153  // FIXME: Timestamp is not set in encoded file at all
154  oc->timestamp = av_gettime();
155 
156  // Alternatively set date in metadata
157  time_t rawtime;
158  struct tm *timeinfo;
159  char datestr[20];
160  time(&rawtime);
161  timeinfo = localtime(&rawtime);
162  strftime(datestr, 20, "%Y-%m-%d %H:%M:%S", timeinfo);
163  av_metadata_set2(&oc->metadata, "date", datestr, 0);
164 
165  // Add a new stream to video file
166  st = av_new_stream(oc, codec->id);
167  if (!st) {
168  errMsg_ = "Could not create video stream";
169  return -1;
170  }
171 
172  // Set default codec context values
173  avcodec_get_context_defaults2(st->codec, AVMEDIA_TYPE_VIDEO);
174 
175  // Set codec context parameters
176  c = st->codec;
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);
180  c->width = width_;
181  c->height = height_;
182  c->gop_size = gopSize_;
183  c->bit_rate = bitrate_;
184  c->max_b_frames = maxBFrames_;
185 
186  // TODO: Unused paramaters
187  //c->sample_aspect_ratio;
188  //c->bits_per_raw_sample;
189  //c->chroma_sample_location;
190 
191  // Set fps and timebase
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);
199 
200  // Select pixel format
201  switch (codec->id) {
202  case CODEC_ID_HUFFYUV:
203  c->pix_fmt = PIX_FMT_YUV422P;
204  break;
205  case CODEC_ID_MJPEG:
206  case CODEC_ID_LJPEG:
207  c->pix_fmt = PIX_FMT_YUVJ420P;
208  break;
209  case CODEC_ID_FFV1:
210  default:
211  c->pix_fmt = PIX_FMT_YUV420P;
212  break;
213  }
214 
215  // Set stream parameters
216  st->sample_aspect_ratio = c->sample_aspect_ratio;
217 
218  // Set global header if needed
219  if (oc->oformat->flags & AVFMT_GLOBALHEADER)
220  c->flags |= CODEC_FLAG_GLOBAL_HEADER;
221 
222  // Set video file parameters
223  if (av_set_parameters(oc, NULL) < 0) {
224  errMsg_ = "invalid encoding parameters";
225  return -1;
226  }
227 
228  // Open codec
229  if (avcodec_open(c, codec) < 0) {
230  errMsg_ = "Could not open codec";
231  return -1;
232  }
233 
234  // Open output file
235  if (url_fopen(&oc->pb, oc->filename, URL_WRONLY) < 0) {
236  errMsg_ = "Could not open output file";
237  return -1;
238  }
239 
240  // Allocate output buffer
241  bufferSize_ = c->width * c->height * 3;
242  pBuffer_ = (uint8_t *) av_malloc(bufferSize_);
243  if (!pBuffer_) {
244  errMsg_ = "Could not allocate output buffer";
245  return -1;
246  }
247 
248  // Allocate encoded raw picture
249  pPict_ = avcodec_alloc_frame();
250  if (!pPict_) {
251  errMsg_ = "Could not allocate raw picture";
252  return -1;
253  }
254 
255  // Allocate encoded raw picture buffer
256  int size = avpicture_get_size(c->pix_fmt, c->width, c->height);
257  pPictBuffer_ = (uint8_t *) av_malloc(size);
258  if (!pPictBuffer_) {
259  errMsg_ = "Could not allocate raw picture buffer";
260  return -1;
261  }
262 
263  // Setup the planes
264  if (!avpicture_fill((AVPicture *) pPict_, pPictBuffer_, c->pix_fmt, c->width, c->height)) {
265  errMsg_ = "Could not fill raw picture buffer";
266  return -1;
267  }
268 
269  // Allocate input picture
270  pInputPict_ = avcodec_alloc_frame();
271  if (!pInputPict_) {
272  errMsg_ = "Could not allocate input picture";
273  return -1;
274  }
275 
276  // Write header
277  if (av_write_header(oc) < 0) {
278  errMsg_ = "Could not write header";
279  return -1;
280  }
281 
282  // Dump format information
283  dump_format(oc, 0, oc->filename, 1);
284 
285  pFormatCtx_ = oc;
286 
287  return 0;
288 }
289 
291 {
292  AVFormatContext *oc = pFormatCtx_;
293  AVStream *st = NULL;
294  AVCodecContext *c = NULL;
295 
296  if (oc) {
297  st = oc->streams[0];
298  if (st) {
299  c = st->codec;
300  }
301  }
302 
303  // Write trailer
304  if (oc)
305  av_write_trailer(oc);
306 
307  // Close video codec
308  if (c)
309  avcodec_close(c);
310 
311  // Close video file
312  if (oc)
313  url_fclose(oc->pb);
314 
315  // Free pointers
316  av_free(pPict_);
317  av_free(pInputPict_);
318  av_free(pBuffer_);
319  av_free(c);
320  av_free(st);
321  av_free(oc);
322 
323  Init_();
324 
325  return 0;
326 }
327 
329 {
330  int ret = 0;
331  if (!pFormatCtx_) {
332  errMsg_ = "Video output file is not opened";
333  return -1;
334  }
335 
336  AVFormatContext *oc = pFormatCtx_;
337  AVStream *st = oc->streams[0];
338  AVCodecContext *c = st->codec;
339  AVPacket pkt;
340  int64_t delta;
341  enum PixelFormat inputPixFmt;
342 
343  // Get realtime presentation timestamp
344  if (realtime_) {
345  if (!oc->start_time_realtime) {
346  oc->start_time_realtime = av_gettime();
347  pts_ = 0;
348  }
349  else {
350  delta = av_gettime() - oc->start_time_realtime;
351  pts_ = delta * (float) st->time_base.den / (float) st->time_base.num / (float) 1000000;
352  }
353  }
354 
355 
356  //make working copy
357  Image<unsigned char> workImg,tmpImg;
359  Image<float> tmpFL(img);
360  ret =tmpFL.ScaleShiftBetween(0,255);
361  if(ret != 0) { BIASERR("Could not ScaleShift float images!"); return -1;}
362 
364  if(ret != 0){ BIASERR("Could not convert Storagetype of image!"); return -1;}
365  }
366  else
367  workImg=img;
368 
369  // if invalid color model set to grey or RGB
370  if(workImg.GetColorModel() == ImageBase::CM_invalid){
371  if(workImg.GetChannelCount() == 3)
373  else if(workImg.GetChannelCount() == 2)
375  else
377  }
378 
379  // Get pixel format of image and convert, else copy to workImg
380  inputPixFmt = GetPixelFormat_(workImg.GetColorModel());
381  if (inputPixFmt == PIX_FMT_NONE) {
382  tmpImg = workImg;
383  ret = ImageConvert::ToRGB(tmpImg,workImg);
384  if(ret != 0) BIASERR("Could not convert image to rgb!");
385  }
386 
387  inputPixFmt = GetPixelFormat_(workImg.GetColorModel());
388  if (inputPixFmt == PIX_FMT_NONE) {
389  errMsg_ = "Input color model not supported";
390  return -1;
391  }
392 
393  // Check size of image
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)){
397  tmpImg = workImg;
398  ret = rescaler.Downsample(tmpImg,workImg,c->width,c->height);
399  if(ret != 0) BIASERR("Could not downsample image to requested size!");
400  }
401  else{
402  tmpImg = workImg;
403  ret = rescaler.Upsample(tmpImg,workImg,c->width,c->height);
404  if(ret != 0) BIASERR("Could not upsample image to requested size!");
405  }
406  }
407  if (workImg.GetSize() != (unsigned) avpicture_get_size(inputPixFmt, c->width, c->height)) {
408  stringstream m;
409  m<<"Image size:"<<workImg.GetWidth()<<"x"<<workImg.GetHeight()
410  <<"does not match video output size:"<<c->width<<"x"<<c->height;
411  errMsg_ = m.str();
412  return -1;
413  }
414 
415  // Copy image to input picture
416  avpicture_fill((AVPicture *) pInputPict_, (uint8_t *) workImg.GetImageData(), inputPixFmt, c->width, c->height);
417 
418  // Get color convert context
419  pSwsCtx_ = sws_getCachedContext(pSwsCtx_, workImg.GetWidth(), workImg.GetHeight(), inputPixFmt, c->width, c->height, c->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);
420  if (!pSwsCtx_) {
421  errMsg_ = "Could not find color convert context";
422  return -1;
423  }
424 
425  // Convert color of input picture
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";
428  return -1;
429  }
430 
431  // Init packet
432  av_init_packet(&pkt);
433  pkt.stream_index = st->index;
434 
435  if (oc->oformat->flags & AVFMT_RAWPICTURE) {
436  // Write raw picture
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;
441 
442  // Write the frame to the video file
443  ret = av_interleaved_write_frame(oc, &pkt);
444  if (ret < 0) {
445  errMsg_ = "Could not write raw frame";
446  return -1;
447  }
448  }
449  else {
450  // Standard encoding
451  pPict_->quality = st->quality;
452  if (realtime_)
453  pPict_->pts = pts_;
454 
455  // Encode video picture
456  ret = avcodec_encode_video(c, pBuffer_, bufferSize_, pPict_);
457  if (ret < 0) {
458  errMsg_ = "Video encoding failed";
459  return -1;
460  }
461 
462  // Dump some info about the encoded frame
463  //printf("frame=%5d dts=%5d pts=%5ld\n", c->coded_frame->coded_picture_number, c->coded_frame->display_picture_number, c->coded_frame->pts);
464 
465  if (ret > 0) {
466  pkt.data = pBuffer_;
467  pkt.size = ret;
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);
470  else
471  pkt.pts = c->coded_frame->pts;
472  if (c->coded_frame->key_frame)
473  pkt.flags |= AV_PKT_FLAG_KEY;
474 
475  // Write the frame to the video file
476  ret = av_interleaved_write_frame(oc, &pkt);
477  if (ret < 0) {
478  errMsg_ = "Could not write frame";
479  return -1;
480  }
481  }
482  }
483 
484  return 0;
485 }
486 
487 int VideoSink_FFmpeg::AddFrame(string filename)
488 {
489  ImageBase image;
490  ImageIO::Load(filename, image);
491  return AddFrame(image);
492 }
493 
494 int VideoSink_FFmpeg::AddFrames(vector<string> filenames)
495 {
496  int ret = 0;
497  vector<string>::iterator f;
498  for (f = filenames.begin(); f != filenames.end() && ret == 0; ++f)
499  ret = AddFrame(*f);
500  return ret;
501 }
502 
504 {
505  switch (colorModel) {
506  case ImageBase::CM_Grey: return PIX_FMT_GRAY8;
507  case ImageBase::CM_GreyA: return PIX_FMT_GRAY16;
508  case ImageBase::CM_RGB: return PIX_FMT_RGB24;
509  case ImageBase::CM_BGR: return PIX_FMT_BGR24;
510  case ImageBase::CM_RGBA: return PIX_FMT_RGBA;
511  case ImageBase::CM_BGRA: return PIX_FMT_BGRA;
512  case ImageBase::CM_YUYV422: return PIX_FMT_YUYV422;
513  case ImageBase::CM_UYVY422: return PIX_FMT_UYVY422;
514  case ImageBase::CM_YUV420P: return PIX_FMT_YUV420P;
515  case ImageBase::CM_YUV444: return PIX_FMT_YUV444P;
516  case ImageBase::CM_YUV411: return PIX_FMT_YUV411P;
517  default: return PIX_FMT_NONE;
518  }
519 }
EColorModel
These are the most often used color models.
Definition: ImageBase.hh:127
YUYV422, 2 channels, full luminance Y, subsampled half U,V.
Definition: ImageBase.hh:133
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.
gray values, 1 channel
Definition: ImageBase.hh:130
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 ...
Definition: Image.cpp:1118
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.
Definition: ImageBase.hh:137
int AddFrame(const ImageBase &image)
Add an Image to the stream and write it to the video output file.
void SetColorModel(EColorModel Model)
Definition: ImageBase.hh:561
int Downsample(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
generic downsample function.
Definition: Rescale.cpp:111
unsigned int GetWidth() const
Definition: ImageBase.hh:312
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...
Definition: ImageBase.hh:135
color values, 3 channels, order: blue,green,red
Definition: ImageBase.hh:132
void SetDefaults()
Reset all user parameters to default values.
CM_YUV444, 3 channels, all channels have full data.
Definition: ImageBase.hh:136
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.
Definition: ImageBase.hh:382
color values, 3 channels, order: red,green,blue
Definition: ImageBase.hh:131
unsigned int GetHeight() const
Definition: ImageBase.hh:319
int Upsample(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
generic upsample function
Definition: Rescale.cpp:1157
UYVY422, 2 channels, full luminance Y, subsampled half U,V inverse order.
Definition: ImageBase.hh:134
void SetBitrate(int bitrate)
Set bitrate in bits per second.
const StorageType * GetImageData() const
overloaded GetImageData() from ImageBase
Definition: Image.hh:137
int Open(std::string filename)
Open a file for video output and init the codec.
RGBA, 4 channels, order: red,green,blue,alpha.
Definition: ImageBase.hh:141
enum EColorModel GetColorModel() const
Definition: ImageBase.hh:407
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...
Definition: ImageIO.cpp:141
invalid (not set) image format
Definition: ImageBase.hh:129
enum EStorageType GetStorageType() const
Definition: ImageBase.hh:414
VideoSink_FFmpeg()
Standard constructor.
(8bit) unsigned char image storage type
Definition: ImageBase.hh:112
double realtime_(void)
Definition: Timing.cpp:72
GreyA, 2 channels, grey plus Alpha.
Definition: ImageBase.hh:142
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.
Definition: ImageBase.hh:102
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...
Definition: ImageBase.hh:361
BGRA color values, 4 channels, order: blue,green,red,alpha.
Definition: ImageBase.hh:150