Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
VideoSink.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 
26 #include "VideoSink.hh"
27 #include <VideoSource/VideoSource_Disk.hh>
28 
29 using namespace std;
30 
32  : _Bitrate(-1), _BPP(4)
33 {
34  static bool firstCall = true;
35  if (firstCall)
36  {
37  avcodec_init();
38  av_register_all();
39  firstCall = false;
40  }
41 }
42 BIAS::VideoSink::VideoSink(std::string Video)
43  : _Video(Video)
44 {
45  VideoSink();
46 }
47 BIAS::VideoSink::VideoSink(std::vector<std::string> Images)
48  : _ImgFiles(Images)
49 {
50  VideoSink();
51 }
52 BIAS::VideoSink::VideoSink(std::vector<std::string> Images, std::string Video)
53  : _ImgFiles(Images), _Video(Video)
54 {
55  VideoSink();
56 }
58 {
59 }
60 
62 {
63  _ImgFiles.push_back(Image);
64 }
65 void BIAS::VideoSink::AddImages(std::vector<std::string> Images)
66 {
67  _ImgFiles.insert(_ImgFiles.end(), Images.begin(), Images.end());
68 }
69 
70 void BIAS::VideoSink::SetOutputVideo(std::string Video)
71 {
72  _Video = Video;
73 }
74 void BIAS::VideoSink::SetFPS(float FPS)
75 {
76  _FPS = FPS;
77 }
78 
79 void BIAS::VideoSink::SetBitrate(int Bitrate)
80 {
81  _Bitrate = Bitrate;
82  _BPP = -1;
83 }
84 void BIAS::VideoSink::SetBPP(double BPP)
85 {
86  _BPP = BPP;
87  _Bitrate = -1;
88 }
89 
90 /*
91 void MakeImagePlanar(BIAS::Image<char> &img)
92 {
93  int size = img.GetWidth() * img.GetHeight();
94  int channels = img.GetChannelCount();
95  char *cp = (char*)malloc(size * channels);
96  char *dat = img.GetImageData();
97  memcpy(cp, dat, size * channels);
98  for (int i = 0; i < size; i++)
99  {
100  for (int c = 0; c < channels; c++)
101  {
102  *(dat + c * size + i) = *(cp + channels * i + c);
103  }
104  }
105  free(cp);
106  img.SetInterleaved(false);
107 }
108 */
109 
110 void BIAS::VideoSink::_RGB888pToYUV420p(uint8_t *rgb, uint8_t *yuv,
111  int width, int height)
112 {
113  /*
114  Y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16
115  Cr = V = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128
116  Cb = U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128
117  (www.fourcc.org/fccyvrgb.php)
118  */
119  int size = width * height;
120  int r;
121  int g;
122  int b;
123  int p;
124  uint8_t *u;
125 
126  for (int y = 0; y < height; y++)
127  {
128  for (int x = 0; x < width; x++)
129  {
130  p = y*width + x;
131  r = *(rgb + p);
132  g = *(rgb + size + p);
133  b = *(rgb + 2*size + p);
134 
135  // Y'
136  *(yuv + p) = (0.257*r) + (0.504*g) + (0.098*b) + 16;
137  // Only 1 U and V value for 2x2 Y' values
138  if (y % 2 == 0 && x % 2 == 0)
139  {
140  // Calculate average color of the 4 pixels
141  r = (r
142  + *(rgb + p + 1)
143  + *(rgb + p + width)
144  + *(rgb + p + width + 1)) / 4;
145  g = (g
146  + *(rgb + size + p + 1)
147  + *(rgb + size + p + width)
148  + *(rgb + size + p + width + 1)) / 4;
149  b = (r
150  + *(rgb + 2*size + p + 1)
151  + *(rgb + 2*size + p + width)
152  + *(rgb + 2*size + p + width + 1)) / 4;
153  // U
154  u = yuv + size + (y/2) * (width/2) + x/2;
155  *u = -(0.148*r) - (0.291*g) + (0.439*b) + 128;
156  // V
157  *(u + size/4) = (0.439*r) - (0.368*g) - (0.071*b) + 128;
158  }
159  }
160  }
161 }
162 
164 {
165  int outSize;
166  int size;
167  int outbufSize;
168  FILE *f;
169  uint8_t *outbuf;
170  uint8_t *pictBuf;
171  uint8_t *yuvBuf;
172  AVFrame *pict;
173  AVFrame *yuvPict;
174  int w;
175  int h;
176  Image<char> img;
177 
178  if (!_SetupVideoSource())
179  return false;
180 
181  w = _VSD.GetWidth();
182  h = _VSD.GetHeight();
183  size = w * h;
184 
185  _Codec = avcodec_find_encoder(CODEC_ID_MPEG1VIDEO);
186  if (!_Codec)
187  {
188  _ErrMsg = "Codec not found";
189  return false;
190  }
191  cout << "Privdatasize: " << _Codec->priv_data_size << endl;
192 
193  _CodecCtx = avcodec_alloc_context();
194  pict = avcodec_alloc_frame();
195  yuvPict = avcodec_alloc_frame();
196 
197  int bitrate = _Bitrate;
198  if (bitrate < 0)
199  bitrate = _BPP * size;
200  _CodecCtx->bit_rate = bitrate;
201  _CodecCtx->width = w;
202  _CodecCtx->height = h;
203  _CodecCtx->time_base.num = 1;
204  _CodecCtx->time_base.den = _FPS;
205  _CodecCtx->gop_size = 10;
206  _CodecCtx->pix_fmt = PIX_FMT_YUV420P;
207  _CodecCtx->priv_data = (void*)"title=BIAS FFMPEG Encoder";
208 
209  if (avcodec_open(_CodecCtx, _Codec) < 0)
210  {
211  _ErrMsg = "Could not open codec";
212  return false;
213  }
214 
215  f = fopen(_Video.c_str(), "wb");
216  if (!f)
217  {
218  _ErrMsg = string("Could not open output file: ") + _Video;
219  return false;
220  }
221 
222  outbufSize = 100000;
223  outbuf = (uint8_t*)malloc(outbufSize);
224  if (!_IsYUV)
225  pictBuf = (uint8_t*)malloc(size * 3); // Size for RGB
226  else
227  pictBuf = (uint8_t*)malloc((size * 3) / 2); // Size for YUV420
228 
229  pict->linesize[0] = w;
230  pict->linesize[1] = w;
231  pict->linesize[2] = w;
232  pict->data[0] = pictBuf;
233  pict->data[1] = pictBuf + size;
234  pict->data[2] = pictBuf + size + size;
235 
236  if (!_IsYUV)
237  {
238  yuvBuf = (uint8_t*)malloc((size * 3) / 2); // Size for YUV420
239 
240  yuvPict->linesize[0] = w;
241  yuvPict->linesize[1] = w / 2;
242  yuvPict->linesize[2] = w / 2;
243  yuvPict->data[0] = yuvBuf;
244  yuvPict->data[1] = yuvBuf + size;
245  yuvPict->data[2] = yuvBuf + size + size / 4;
246  }
247  else
248  {
249  yuvPict = pict;
250  yuvBuf = pictBuf;
251  }
252 
253  _VSD.PreGrab();
254  int i = 0;
255  while (_VSD.GetNumFramesRemaining() != 0)
256  {
257  fflush(stdout);
258 
259  if (_VSD.GrabSingle(img) != 0)
260  {
261  _ErrMsg = "Error grabbing image";
262  return false;
263  }
264 
265  // Need to convert colormodel?
266  if (!_IsYUV)
267  {
268  ImageConvert::ToPlanar(img, img);
269  //memcpy(pictBuf, img.GetImageData(), size * 3);
270  //sws_scale(_SwsCtx, pict->data, pict->linesize, 0,
271  // h, yuvPict->data, yuvPict->linesize);
272  _RGB888pToYUV420p((uint8_t*)img.GetImageData(), yuvBuf, w, h);
273  }
274  else
275  {
276  memcpy(yuvBuf, img.GetImageData(), (size * 3) / 2);
277  }
278 
279  outSize = avcodec_encode_video(_CodecCtx, outbuf, outbufSize, yuvPict);
280  fwrite(outbuf, 1, outSize, f);
281 
282  cout << "Frame " << i << ", remaining: "
283  << _VSD.GetNumFramesRemaining() << endl;
284  i++;
285  }
286  _VSD.PostGrab();
287 
288  outbuf[0] = 0x00;
289  outbuf[1] = 0x00;
290  outbuf[2] = 0x01;
291  outbuf[3] = 0xb7;
292  fwrite(outbuf, sizeof(uint8_t), 4, f);
293  fclose(f);
294  free(pictBuf);
295  if (yuvBuf)
296  free(yuvBuf);
297  free(outbuf);
298 
299  avcodec_close(_CodecCtx);
300  av_free(_CodecCtx);
301  av_free(pict);
302  if (yuvPict)
303  av_free(yuvPict);
304 
305  return true;
306 }
307 
309 {
310  return _ErrMsg;
311 }
312 
313 
315 {
316  _VSD.SetLoopMode(false);
317  _VSD.SetColorModel(ImageBase::CM_YUV420P);
318  if (_VSD.OpenDevice(_ImgFiles) != 0)
319  {
320  _ErrMsg = "Loading images failed";
321  return false;
322  }
323  ImageBase::EColorModel cm = _VSD.GetColorModel();
324  if (cm == ImageBase::CM_RGB)
325  {
326  //_SetupSwsContext(PIX_FMT_RGB24);
327  _IsYUV = false;
328  }
329  else if (cm != ImageBase::CM_YUV420P)
330  {
331  _ErrMsg = "VideoSource returns unsupported colormodel";
332  return false;
333  }
334  else
335  _IsYUV = true;
336 
337  return true;
338 }
339 
340 /*
341 bool BIAS::VideoSink::_SetupSwsContext(PixelFormat fromFmt, int width,
342  int height)
343 {
344  int w = _VSD.GetWidth();
345  int h = _VSD.GetHeight();
346 
347  if (width == 0 && height == 0)
348  {
349  width = w;
350  height = h;
351  }
352  // Resize but maintain aspect ratio
353  else if (width != 0 && height == 0)
354  {
355  height = (float)width / w * h;
356  }
357  else if (width == 0 && height != 0)
358  {
359  width = (float)height / h * w;
360  }
361 
362  _SwsCtx = sws_getContext(w, h, fromFmt,
363  width, height, PIX_FMT_YUV420P,
364  SWS_BICUBIC, NULL, NULL, NULL);
365  if (_SwsCtx == NULL)
366  {
367  _ErrMsg = "Cannot initialize the conversion context!";
368  return false;
369  }
370  return true;
371 }
372 */
EColorModel
These are the most often used color models.
Definition: ImageBase.hh:127
void SetBitrate(int Bitrate)
Set the bitrate of the output video.
Definition: VideoSink.cpp:79
void SetFPS(float FPS)
Set the framerate for the video.
Definition: VideoSink.cpp:74
bool _SetupVideoSource()
Definition: VideoSink.cpp:314
bool Encode()
Encode the video.
Definition: VideoSink.cpp:163
static void _RGB888pToYUV420p(uint8_t *rgb, uint8_t *yuv, int width, int height)
Convert RGB888p data to Y&#39;UV420p.
Definition: VideoSink.cpp:110
static BIASImageBase_EXPORT int ToPlanar(const Image< StorageType > &source, Image< StorageType > &dest)
Converts the existing image to an planar version.
Definition: ToPlanar.cpp:33
unsigned int GetWidth() const
Definition: ImageBase.hh:312
YUV420P, 2 channels, full luminance Y, 1 U, 1 V. Y, U and V are grouped together for better compressi...
Definition: ImageBase.hh:135
std::string GetErrMsg()
Return the last produced errormessage.
Definition: VideoSink.cpp:308
color values, 3 channels, order: red,green,blue
Definition: ImageBase.hh:131
void SetBPP(double BPP)
Set the bits per pixel of the output video.
Definition: VideoSink.cpp:84
The image template class for specific storage types.
Definition: Image.hh:78
const StorageType * GetImageData() const
overloaded GetImageData() from ImageBase
Definition: Image.hh:137
void SetOutputVideo(std::string Video)
Set the file where the video will be written to.
Definition: VideoSink.cpp:70
void AddImage(std::string Image)
Append an image to the end of the list.
Definition: VideoSink.cpp:61
void AddImages(std::vector< std::string > Images)
Definition: VideoSink.cpp:65