Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
VideoSource_FFmpeg.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 #include "VideoSource_FFmpeg.hh"
26 #include <sstream>
27 
28 using namespace BIAS;
29 using namespace std;
30 
32 {
33  av_register_all();
34  Init_();
35 }
36 
38 {
39  CloseDevice();
40 }
41 
43 {
44  pFormatCtx_ = NULL;
45  streamIndex_ = -1;
46  pFrame_ = NULL;
47  pOutputFrame_ = NULL;
48  pBuffer_ = NULL;
49  outputPixFmt_ = PIX_FMT_RGB24;
50  pSwsCtx_ = NULL;
51  numFrames_ = 0;
52  frameNumber_ = 0;
53  timeBaseNum_ = 1;
54  timeBaseDen_ = 1;
55  timestamp_ = -1;
56  dateStr_ = NULL;
57  duration_ = -1;
58  errMsg_ = "";
59  pFormatCtx_ = NULL;
60  errMsg_ = "";
61  frameNumber_ = 0;
62  pts_ = 0;
63 
65  BytesPerPixel_ = 1.0;
66  ColorChannels_ = 3;
68 }
69 
70 int VideoSource_FFmpeg::OpenDevice(const char *filename)
71 {
73  errMsg_ = "VideoSource_FFmpeg already initialized. Call CloseDevice() first.";
74  return -1;
75  }
76 
77  AVFormatContext *ic;
78  AVStream *st;
79  AVCodecContext *c;
80  AVCodec *codec;
81 
82  // Open video file
83  if (av_open_input_file(&ic, filename, NULL, 0, NULL) < 0) {
84  errMsg_ = "Could not open video file";
85  return -1;
86  }
87 
88  // Retrieve stream information
89  if (av_find_stream_info(ic) < 0) {
90  errMsg_ = "Could not find stream information";
91  return -1;
92  }
93 
94  // Dump format information
95  dump_format(ic, 0, filename, false);
96 
97  // Select video stream
98  streamIndex_ = -1;
99  if (DeviceChannel_ >= 0) {
100  // Select stream specified by user
101  if (ic->streams[DeviceChannel_]->codec->codec_type == CODEC_TYPE_VIDEO)
103  else
104  cout << "Video stream not found. Falling back to first video stream" << endl;
105  }
106  if (streamIndex_ == -1) {
107  // Select first video stream
108  for (unsigned int i = 0; i < ic->nb_streams; i++) {
109  if (ic->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
111  break;
112  }
113  }
114  }
115  if (streamIndex_ == -1) {
116  errMsg_ = "Could not find a video stream";
117  return -1;
118  }
119 
120  st = ic->streams[streamIndex_];
121  c = st->codec;
122 
123  // Find decoder
124  codec = avcodec_find_decoder(c->codec_id);
125  if (!codec) {
126  errMsg_ = "Could not find decoder";
127  return -1;
128  }
129 
130  // Open decoder
131  if (avcodec_open(c, codec) < 0) {
132  errMsg_ = "Could not open decoder";
133  return -1;
134  }
135 
136  // Allocate video frame
137  pFrame_ = avcodec_alloc_frame();
138  if (!pFrame_) {
139  errMsg_ = "Could not allocate video frame";
140  return -1;
141  }
142 
143  // Allocate output frame
144  pOutputFrame_ = avcodec_alloc_frame();
145  if (!pOutputFrame_) {
146  errMsg_ = "Could not allocate output frame";
147  return -1;
148  }
149 
150  // Get some video stream parameters
151  Width_ = c->width;
152  Height_ = c->height;
153  FramesPerSecond_ = st->r_frame_rate.num / (float) st->r_frame_rate.den;
154  timeBaseNum_ = st->time_base.num;
155  timeBaseDen_ = st->time_base.den;
156  timestamp_ = ic->timestamp;
157  duration_ = ic->duration;
158  numFrames_ = st->nb_frames;
159 
160  // Try to get date string from metadata or filename
161  AVMetadataTag *mtag;
162  mtag = av_metadata_get(ic->metadata, "date", NULL, 0);
163  if (mtag)
164  dateStr_ = mtag->value;
165  mtag = av_metadata_get(st->metadata, "date", NULL, 0);
166  if (mtag)
167  dateStr_ = mtag->value;
168  if (!dateStr_)
169  dateStr_ = ExtractDateString_(filename);
170 
171  // Get video frame size
172  ImageSize_ = avpicture_get_size(outputPixFmt_, Width_, Height_);
173  if (ImageSize_ < 0) {
174  errMsg_ = "Could not calculate video frame size";
175  return -1;
176  }
177 
178  // Allocate video frame buffer
179  pBuffer_ = (uint8_t *) av_malloc(ImageSize_ * sizeof(uint8_t));
180  if (!pBuffer_) {
181  errMsg_ = "Could not allocate video frame buffer";
182  return -1;
183  }
184 
185  // Fill video frame buffer
186  if (avpicture_fill((AVPicture *) pOutputFrame_, pBuffer_, outputPixFmt_, Width_, Height_) < 0) {
187  errMsg_ = "Could not fill video frame buffer";
188  return -1;
189  }
190 
191  pFormatCtx_ = ic;
192  CompleteInitialized_ = true;
193 
194  return 0;
195 }
196 
198 {
199  AVFormatContext *ic = pFormatCtx_;
200  AVStream *st = NULL;
201  AVCodecContext *c = NULL;
202 
203  if (ic) {
204  st = ic->streams[streamIndex_];
205  if (st) {
206  c = st->codec;
207  }
208  }
209 
210  if (Active_)
211  PostGrab();
212 
213  Grabbing_ = false;
214  CompleteInitialized_ = false;
215 
216  // Free buffers and frames
217  av_free(pBuffer_);
218  av_free(pOutputFrame_);
219  av_free(pFrame_);
220 
221  // Close the codec
222  if (c)
223  avcodec_close(c);
224 
225  // Close the video file
226  if (ic)
227  av_close_input_file(ic);
228 
229  Init_();
230 
231  return 0;
232 }
233 
235 {
236  assert(!image.IsEmpty());
237 
238  if (!Active_)
239  BEXCEPTION("VideoSource Object not active, use PreGrab()");
240 
241  if (Grabbing_)
242  BEXCEPTION("VideoSource Object is already grabbing()");
243 
244  Grabbing_ = true;
245 
246  AVFormatContext *ic = pFormatCtx_;
247  AVStream *st = ic->streams[streamIndex_];
248  AVCodecContext *c = st->codec;
249  AVPacket pkt;
250  int ret, gotPicture;
251  MetaData *m;
252  ostringstream ascii;
253 
254  // Read a frame
255  bool done = false;
256  while (!done) {
257  ret = av_read_frame(ic, &pkt);
258  if (ret < 0) {
259  errMsg_ = ret == EOF ? "End of video file reached" : "Could not read video frame";
260  Grabbing_ = false;
261  return ret;
262  }
263 
264  if (pkt.stream_index == streamIndex_) {
265  ret = avcodec_decode_video2(c, pFrame_, &gotPicture, &pkt);
266  if (ret < 0) {
267  errMsg_ = "Could not decode video frame";
268  Grabbing_ = false;
269  return -1;
270  }
271 
272  if (gotPicture) {
273  // Color conversion
274  pSwsCtx_ = sws_getCachedContext(pSwsCtx_, c->width, c->height, c->pix_fmt, c->width, c->height, outputPixFmt_, SWS_BICUBIC, NULL, NULL, NULL);
275  if (!pSwsCtx_) {
276  errMsg_ = "Could not initialize a conversion context";
277  Grabbing_ = false;
278  return -1;
279  }
280  void *data = image.GetImageData();
281  sws_scale(pSwsCtx_, pFrame_->data, pFrame_->linesize, 0, c->height, (uint8_t **) &data, pOutputFrame_->linesize);
282 
283  // Generate new uid of image
284  image.InvalidateUID();
285  image.SetUID(UUID::GenerateUUID());
286 
287  // Calculate pts in microseconds
288  pts_ = pkt.pts < 0 ? pkt.dts : pkt.pts;
289  pts_ = pts_ * 1000000 * st->time_base.num / st->time_base.den;
290 
291  // Set metadata of image
292  m = image.GetMetaData();
293  ascii.str("");
294  ascii.clear();
295  ascii << frameNumber_;
296  m->Add("#[num]", ascii.str());
297  ascii.str("");
298  ascii.clear();
299  ascii << pts_;
300  m->Add("#[pts]", ascii.str());
301  image.SetMetaData(*m);
302 
303  frameNumber_++;
304  done = true;
305  }
306  }
307  }
308 
309  Grabbing_ = false;
310 
311  return 0;
312 }
313 
315 {
316  AVFormatContext *ic = pFormatCtx_;
317  AVStream *st = ic->streams[streamIndex_];
318  AVCodecContext *c = st->codec;
319 
320  /*if (avformat_seek_file(ic, streamIndex_, 0, frame, frame,
321 AVSEEK_FLAG_FRAME) < 0) {
322  errMsg_ ="Could not seek frame";
323  return -1;
324  }*/
325 
326  int64_t timestamp = frame * st->time_base.den / st->time_base.num /
328  cout << timestamp << endl;
329  if (av_seek_frame(ic, streamIndex_, timestamp, 0) < 0) {
330  errMsg_ ="Could not seek frame";
331  return -1;
332  }
333  avcodec_flush_buffers(c);
334 
335  return 0;
336 }
337 
339 {
340  AVFormatContext *ic = pFormatCtx_;
341  AVStream *st = ic->streams[streamIndex_];
342  AVCodecContext *c = st->codec;
343  int64_t ts = ms * st->time_base.den / st->time_base.num / 1000;
344 
345  /*if (avformat_seek_file(ic, streamIndex_, 0, ts, ts, 0) < 0) {
346  errMsg_ = "Could not seek time";
347  return -1;
348  }*/
349  if (av_seek_frame(ic, streamIndex_, ts, 0) < 0) {
350  errMsg_ ="Could not seek frame";
351  return -1;
352  }
353  avcodec_flush_buffers(c);
354 
355  return 0;
356 }
357 
359 {
360  switch (mode) {
361  case ImageBase::CM_Grey:
362  outputPixFmt_ = PIX_FMT_GRAY8;
363  ColorMode_ = mode;
364  ColorChannels_ = 1;
365  break;
366  case ImageBase::CM_RGB:
367  outputPixFmt_ = PIX_FMT_RGB24;
368  ColorMode_ = mode;
369  ColorChannels_ = 3;
370  break;
371  case ImageBase::CM_BGR:
372  outputPixFmt_ = PIX_FMT_BGR24;
373  ColorMode_ = mode;
374  ColorChannels_ = 3;
375  break;
376  case ImageBase::CM_RGBA:
377  outputPixFmt_ = PIX_FMT_RGBA;
378  ColorMode_ = mode;
379  ColorChannels_ = 4;
380  break;
381  case ImageBase::CM_BGRA:
382  outputPixFmt_ = PIX_FMT_BGRA;
383  ColorMode_ = mode;
384  ColorChannels_ = 4;
385  break;
387  outputPixFmt_ = PIX_FMT_YUYV422;
388  ColorMode_ = mode;
389  ColorChannels_ = 2;
390  break;
392  outputPixFmt_ = PIX_FMT_UYVY422;
393  ColorMode_ = mode;
394  ColorChannels_ = 2;
395  break;
397  outputPixFmt_ = PIX_FMT_YUV420P;
398  ColorMode_ = mode;
399  ColorChannels_ = 2;
400  break;
401  default:
402  errMsg_ = "Unsupported color model";
403  return -1;
404  break;
405  }
406 
407  return 0;
408 }
409 
411 {
412  bool done = false;
413  int pos = 0;
414  int size = str.size();
415  char *dateStr;
416  int dateStrSize = 0;
417 
418  dateStr = (char *) malloc(20);
419  dateStr[0] = '\0';
420 
421  while (!done && pos < size) {
422  const char c = str[pos++];
423  switch (c) {
424  case '0':
425  case '1':
426  case '2':
427  case '3':
428  case '4':
429  case '5':
430  case '6':
431  case '7':
432  case '8':
433  case '9':
434  {
435  switch (dateStrSize) {
436  case 4:
437  case 7:
438  dateStr[dateStrSize] = '-';
439  dateStrSize++;
440  break;
441  case 10:
442  dateStr[dateStrSize] = ' ';
443  dateStrSize++;
444  break;
445  case 13:
446  case 16:
447  dateStr[dateStrSize] = ':';
448  dateStrSize++;
449  break;
450  }
451  dateStr[dateStrSize] = c;
452  dateStrSize++;
453  if (dateStrSize >= 19)
454  done = true;
455  break;
456  }
457  case '_':
458  {
459  if (dateStrSize == 10) {
460  dateStr[dateStrSize] = ' ';
461  dateStrSize++;
462  }
463  else {
464  dateStr[0] = '\0';
465  dateStrSize = 0;
466  }
467  break;
468  }
469  default:
470  dateStr[0] = '\0';
471  dateStrSize = 0;
472  break;
473  }
474  }
475 
476  dateStr[dateStrSize] = '\0';
477  if (!done || parse_date(dateStr, 0) < 0)
478  return NULL;
479  else
480  return dateStr;
481 }
int64_t duration_
Stream duration in milliseconds, 0 if unknown.
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
int SeekMs(int ms)
Seek to time in milliseconds in video stream.
int64_t pts_
Presentation timestamp of last decoded frame in microseconds.
virtual int GrabSingle(Camera< unsigned char > &image)
Get the next frame from the video file.
Defines a common interface to different devices.
int streamIndex_
Index of the video stream.
gray values, 1 channel
Definition: ImageBase.hh:130
bool IsEmpty() const
check if ImageData_ points to allocated image buffer or not
Definition: ImageBase.hh:245
std::string errMsg_
The last error message.
MetaData * GetMetaData()
Definition: ImageBase.hh:456
BIAS::ImageBase::EColorModel ColorMode_
Color mode used by camera.
int DeviceChannel_
Device channel.
AVFrame * pFrame_
Video stream frame.
float BytesPerPixel_
BytesPerPixel cannot be int (e.g. it is 1.5 for YUV420p)
void Add(enum AppData::TAppData ID, unsigned int length, char *data)
Add a new binary meta datum.
Definition: MetaData.cpp:317
int64_t numFrames_
Number of frames of the stream, 0 if unknown.
YUV420P, 2 channels, full luminance Y, 1 U, 1 V. Y, U and V are grouped together for better compressi...
Definition: ImageBase.hh:135
bool CompleteInitialized_
Complete_initialized_ is set when OpenDevice(), UseChannel() etc. are done.
int timeBaseNum_
Stream timebase numerator.
int Width_
Image format.
color values, 3 channels, order: blue,green,red
Definition: ImageBase.hh:132
AVFormatContext * pFormatCtx_
Format context for video decoder.
virtual int SetColorModel(ImageBase::EColorModel mode)
Set output color model.
SwsContext * pSwsCtx_
Color conversion context.
bool Grabbing_
Grabbing flag is set and unset in GrabSingle() methods.
virtual int OpenDevice()
selects the first available device to open (e.g.
enum PixelFormat outputPixFmt_
Output frame pixel format.
float FramesPerSecond_
Capturing framerate.
color values, 3 channels, order: red,green,blue
Definition: ImageBase.hh:131
char * ExtractDateString_(std::string str)
Try to extract date string of format &quot;YYYYMMDD_HHMMSS&quot; from string.
UYVY422, 2 channels, full luminance Y, subsampled half U,V inverse order.
Definition: ImageBase.hh:134
int64_t frameNumber_
Number of decoded frames.
int SeekFrame(int64_t frame)
Seek to frame in video stream.
bool Active_
Active flag is set in PreGrab() und unset in PostGrab()
void InvalidateUID()
sets the image&#39;s uid to invalid
Definition: ImageBase.hh:597
int timeBaseDen_
Stream timebase denumerator.
const StorageType * GetImageData() const
overloaded GetImageData() from ImageBase
Definition: Image.hh:137
void SetUID(const BIAS::UUID &id)
Definition: ImageBase.hh:589
RGBA, 4 channels, order: red,green,blue,alpha.
Definition: ImageBase.hh:141
virtual int PostGrab()
Stop anything started in PreGrab()
this class collects all additional data chunks of type AppData to be written into/read from an image ...
Definition: MetaData.hh:121
unsigned int ImageSize_
Image size, useful for allocating and copying memory.
virtual int CloseDevice()
Close video file.
char * dateStr_
String representation of timestamp_.
virtual ~VideoSource_FFmpeg()
Clean up.
int64_t timestamp_
Stream timestamp.
void Init_()
Called by constructor to init variables.
void SetMetaData(const MetaData &m)
Definition: ImageBase.hh:470
uint8_t * pBuffer_
Ouput frame buffer.
static UUID GenerateUUID(const bool &consecutively=DEFAULT_UUID_CONSECUTIVELY)
static function which simply produces a uuid and returns
Definition: UUID.cpp:235
VideoSource_FFmpeg()
Standard constructor.
BGRA color values, 4 channels, order: blue,green,red,alpha.
Definition: ImageBase.hh:150
AVFrame * pOutputFrame_
Output frame.